diff --git a/HostingApp/Base.lproj/Main.storyboard b/HostingApp/Base.lproj/Main.storyboard index 425cb1a8..1ea515e2 100644 --- a/HostingApp/Base.lproj/Main.storyboard +++ b/HostingApp/Base.lproj/Main.storyboard @@ -1,7 +1,7 @@ - + - + @@ -34,20 +34,20 @@ - + - + - + - + - + - + diff --git a/HostingApp/ViewController.swift b/HostingApp/ViewController.swift index 2d8f558c..a9129b7b 100644 --- a/HostingApp/ViewController.swift +++ b/HostingApp/ViewController.swift @@ -15,10 +15,10 @@ class HostingAppViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillShow"), name: UIKeyboardWillShowNotification, object: nil) - NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidHide"), name: UIKeyboardDidHideNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(HostingAppViewController.keyboardWillShow), name: UIKeyboardWillShowNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(HostingAppViewController.keyboardDidHide), name: UIKeyboardDidHideNotification, object: nil) //NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardWillChangeFrame:"), name: UIKeyboardWillChangeFrameNotification, object: nil) - NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("keyboardDidChangeFrame:"), name: UIKeyboardDidChangeFrameNotification, object: nil) + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(HostingAppViewController.keyboardDidChangeFrame(_:)), name: UIKeyboardDidChangeFrameNotification, object: nil) } override func didReceiveMemoryWarning() { diff --git a/Keyboard/CYRKeyboardButton/CYRKeyboardButton.h b/Keyboard/CYRKeyboardButton/CYRKeyboardButton.h new file mode 100755 index 00000000..77ed698c --- /dev/null +++ b/Keyboard/CYRKeyboardButton/CYRKeyboardButton.h @@ -0,0 +1,155 @@ +// +// CYRKeyboardButton.h +// +// Created by Illya Busigin on 7/19/14. +// Copyright (c) 2014 Cyrillian, Inc. +// Portions Copyright (c) 2013 Nigel Timothy Barber (TurtleBezierPath) +// +// Distributed under MIT license. +// Get the latest version from here: +// +// https://github.com/illyabusigin/CYRKeyboardButton +// +// The MIT License (MIT) +// +// Copyright (c) 2014 Cyrillian, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import +#import "CYRKeyboardButtonView.h" +typedef NS_ENUM(NSUInteger, CYRKeyboardButtonPosition) { + CYRKeyboardButtonPositionLeft, + CYRKeyboardButtonPositionInner, + CYRKeyboardButtonPositionRight, + CYRKeyboardButtonPositionCount +}; + +/** + The style of the keyboard button. You use these constants to set the value of the keyboard button style. + */ +typedef NS_ENUM(NSUInteger, CYRKeyboardButtonStyle) { + /** Keyboard buttons are styled like iPhone keyboard buttons. */ + CYRKeyboardButtonStylePhone, + /** Keyboard buttons are styled like iPad keyboard buttons. */ + CYRKeyboardButtonStyleTablet +}; + +/** + Notifies observers that the keyboard button has been pressed. The affected button is stored in the object parameter of the notification. The userInfo dictionary contains the pressed key and can be accessed with the CYRKeyboardButtonKeyPressedKey key. + */ +extern NSString *const CYRKeyboardButtonPressedNotification; + +/** + Notifies observers that the keyboard button has show the expanded input view. The affected button is stored in the object parameter of the notification. + */ +extern NSString *const CYRKeyboardButtonDidShowExpandedInputNotification; + +/** + Notifies observers that the keyboard button has hidden the expanded input view. The affected button is stored in the object parameter of the notification. + */ +extern NSString *const CYRKeyboardButtonDidHideExpandedInputNotification; + +/** + The key used to fetch the pressed key string from the userInfo dictionary returned when CYRKeyboardButtonPressedNotification is fired. + */ +extern NSString *const CYRKeyboardButtonKeyPressedKey; + +/** + CYRKeyboardButton is a drop-in keyboard button that mimics the look, feel, and functionality of the native iOS keyboard buttons. This button is highly configurable via a variety of styling properties which conform to the UIAppearance protocol. + */ +@interface CYRKeyboardButton : UIControl + +/** + The style of the keyboard button. This determines the basic visual appearance of the keyboard. + @discussion The style value is automatically determined during initialization but can be overriden. + */ +@property (nonatomic, assign) CYRKeyboardButtonStyle style; + + +// Styling + +/** + The font associated with the keyboard button. + @discussion This font only affects the keyboard button's standard view. + */ +@property (nonatomic, strong) UIFont *font UI_APPEARANCE_SELECTOR; + +/** + The font associated with the keyboard button input options. + */ +@property (nonatomic, strong) UIFont *inputOptionsFont UI_APPEARANCE_SELECTOR; + +/** + The default color of the keyboard button. + */ +@property (nonatomic, strong) UIColor *keyColor UI_APPEARANCE_SELECTOR; + +/** + The text color of the keyboard button. + @discussion This color affects both the standard and input option text. + */ +@property (nonatomic, strong) UIColor *keyTextColor UI_APPEARANCE_SELECTOR; + +/** + The shadow color for the keyboard button. + */ +@property (nonatomic, strong) UIColor *keyShadowColor UI_APPEARANCE_SELECTOR; + +/** + The highlighted background color of the keyboard button. + */ +@property (nonatomic, strong) UIColor *keyHighlightedColor UI_APPEARANCE_SELECTOR; + +/** + The position of the keyboard button. This is used to determine where to place the popover key views and is automatically determined when the keyboard button is added to a view and update during layout changes. + */ +@property (nonatomic, readonly) CYRKeyboardButtonPosition position; + +// Configuration + +/** + The string input for the keyboard button. This is the string that would be inserted upon a successful key press. + */ +@property (nonatomic, strong) NSString *input; + +/** + An array of input option strings associated with the keybonard button. The user must tap and hold the keyboard button for 0.3 seconds before the input options will be displayed. + @discussion Input options are automatically positioned based on the keyboard buttons position within its' superview. + */ +@property (nonatomic, strong) NSArray *inputOptions; + +/** + An object that adopts the UITextInput protocol. When a key is pressed the key value is automatically inserted via the textInput object. + @discussion If the textInput object is not the first responder no text will be inserted. + */ +@property (nonatomic, weak) id textInput; + + +@property (nonatomic) BOOL isPanEnabled; + +@property (nonatomic, weak) UIView *forwordingView; + +@property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer; +-(CYRKeyboardButtonView*)showLongPopUpOptions; +- (void)setupInputOptionsConfiguration; +- (void)setupInputOptionsConfigurationWithView:(UIView*)forwordingView; +- (void)tearDownInputOptionsConfigurationWithView:(UIView*)forwordingView; +- (void)tearDownInputOptionsConfiguration; + +@end diff --git a/Keyboard/CYRKeyboardButton/CYRKeyboardButton.m b/Keyboard/CYRKeyboardButton/CYRKeyboardButton.m new file mode 100755 index 00000000..efac6547 --- /dev/null +++ b/Keyboard/CYRKeyboardButton/CYRKeyboardButton.m @@ -0,0 +1,518 @@ +// +// CYRKeyboardButton.m +// +// Created by Illya Busigin on 7/19/14. +// Copyright (c) 2014 Cyrillian, Inc. +// Portions Copyright (c) 2013 Nigel Timothy Barber (TurtleBezierPath) +// +// Distributed under MIT license. +// Get the latest version from here: +// +// https://github.com/illyabusigin/CYRKeyboardButton +// +// The MIT License (MIT) +// +// Copyright (c) 2014 Cyrillian, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "CYRKeyboardButton.h" +#import "CYRKeyboardButtonView.h" + +NSString *const CYRKeyboardButtonPressedNotification = @"CYRKeyboardButtonPressedNotification"; +NSString *const CYRKeyboardButtonDidShowExpandedInputNotification = @"CYRKeyboardButtonDidShowExpandedInputNotification"; +NSString *const CYRKeyboardButtonDidHideExpandedInputNotification = @"CYRKeyboardButtonDidHideExpandedInputNotification"; +NSString *const CYRKeyboardButtonKeyPressedKey = @"CYRKeyboardButtonKeyPressedKey"; + +@interface CYRKeyboardButton () + +@property (nonatomic, strong) UILabel *inputLabel; +@property (nonatomic, strong) CYRKeyboardButtonView *buttonView; +@property (nonatomic, strong) CYRKeyboardButtonView *expandedButtonView; + +@property (nonatomic, assign) CYRKeyboardButtonPosition position; + +// Input options state +@property (nonatomic, strong) UILongPressGestureRecognizer *optionsViewRecognizer; +//@property (nonatomic, strong) UIPanGestureRecognizer *panGestureRecognizer; + +// Internal style +@property (nonatomic, assign) CGFloat keyCornerRadius UI_APPEARANCE_SELECTOR; + +@end + +@implementation CYRKeyboardButton +@synthesize panGestureRecognizer,isPanEnabled; +#pragma mark - UIView + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + switch ([UIDevice currentDevice].userInterfaceIdiom) { + case UIUserInterfaceIdiomPhone: + _style = CYRKeyboardButtonStylePhone; + break; + + case UIUserInterfaceIdiomPad: + _style = CYRKeyboardButtonStyleTablet; + break; + + default: + break; + } + + // Default appearance + _font = [UIFont systemFontOfSize:22.f]; + _inputOptionsFont = [UIFont systemFontOfSize:22.f]; + _keyColor = [UIColor whiteColor]; + _keyTextColor = [UIColor blackColor]; + _keyShadowColor = [UIColor colorWithRed:136 / 255.f green:138 / 255.f blue:142 / 255.f alpha:1]; + _keyHighlightedColor = [UIColor colorWithRed:213/255.f green:214/255.f blue:216/255.f alpha:1]; + + // Styling + self.backgroundColor = [UIColor clearColor]; + self.clipsToBounds = NO; + self.layer.masksToBounds = NO; + self.contentHorizontalAlignment = UIControlContentHorizontalAlignmentCenter; + + // State handling +// [self addTarget:self action:@selector(handleTouchDown) forControlEvents:UIControlEventTouchDown]; +// [self addTarget:self action:@selector(handleTouchUpInside) forControlEvents:UIControlEventTouchUpInside]; + + // Input label + UILabel *inputLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, CGRectGetWidth(frame), CGRectGetHeight(frame))]; + inputLabel.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight; + inputLabel.textAlignment = NSTextAlignmentCenter; + inputLabel.backgroundColor = [UIColor clearColor]; + inputLabel.userInteractionEnabled = NO; + inputLabel.textColor = _keyTextColor; + inputLabel.font = _font; + + [self addSubview:inputLabel]; + _inputLabel = inputLabel; + + [self updateDisplayStyle]; + } + + return self; +} + +- (void)didMoveToSuperview +{ + [self updateButtonPosition]; +} + +- (void)layoutSubviews +{ + [super layoutSubviews]; + + [self setNeedsDisplay]; + + [self updateButtonPosition]; +} + +#pragma mark - UIGestureRecognizerDelegate + +#pragma mark - Overrides + +- (NSString *)description +{ + NSString *description = [NSString stringWithFormat:@"<%@ %p>; frame = %@; input = %@; inputOptions = %@", + NSStringFromClass([self class]), + self, + NSStringFromCGRect(self.frame), + self.input, + self.inputOptions]; + + return description; +} + +//- (void)setInput:(NSString *)input +//{ +// //[self willChangeValueForKey:NSStringFromSelector(@selector(input))]; +// self.input = input; +// //[self didChangeValueForKey:NSStringFromSelector(@selector(input))]; +// +// _inputLabel.text = _input; +//} +// +//- (void)setInputOptions:(NSArray *)inputOptions +//{ +// //[self willChangeValueForKey:NSStringFromSelector(@selector(inputOptions))]; +// self.inputOptions = inputOptions; +// //[self didChangeValueForKey:NSStringFromSelector(@selector(inputOptions))]; +// +//// if (_inputOptions.count > 0) { +//// //[self setupInputOptionsConfiguration]; +//// } else { +//// //[self tearDownInputOptionsConfiguration]; +//// } +//} + +- (void)setStyle:(CYRKeyboardButtonStyle)style +{ + [self willChangeValueForKey:NSStringFromSelector(@selector(style))]; + _style = style; + [self didChangeValueForKey:NSStringFromSelector(@selector(style))]; + + [self updateDisplayStyle]; +} + +- (void)setKeyTextColor:(UIColor *)keyTextColor +{ + if (_keyTextColor != keyTextColor) { + [self willChangeValueForKey:NSStringFromSelector(@selector(keyTextColor))]; + _keyTextColor = keyTextColor; + [self didChangeValueForKey:NSStringFromSelector(@selector(keyTextColor))]; + + _inputLabel.textColor = keyTextColor; + } +} + +- (void)setFont:(UIFont *)font +{ + if (_font != font) { + [self willChangeValueForKey:NSStringFromSelector(@selector(font))]; + _font = font; + [self didChangeValueForKey:NSStringFromSelector(@selector(font))]; + + _inputLabel.font = font; + } +} + +- (void)setTextInput:(id)textInput +{ + NSAssert([textInput conformsToProtocol:@protocol(UITextInput)], @" The text input object must conform to the UITextInput protocol!"); + + [self willChangeValueForKey:NSStringFromSelector(@selector(textInput))]; + _textInput = textInput; + [self didChangeValueForKey:NSStringFromSelector(@selector(textInput))]; +} + +#pragma mark - Internal - UI + +- (void)showInputView +{ + if (_style == CYRKeyboardButtonStylePhone) { + [self hideInputView]; + + self.buttonView = [[CYRKeyboardButtonView alloc] initWithKeyboardButton:self type:CYRKeyboardButtonViewTypeInput]; + + [self.window addSubview:self.buttonView]; + } else { + [self setNeedsDisplay]; + } + +} + +-(CYRKeyboardButtonView*)showLongPopUpOptions +{ + CYRKeyboardButtonView *expandedButtonView = [[CYRKeyboardButtonView alloc] initWithKeyboardButton:self type:CYRKeyboardButtonViewTypeExpanded]; + //NSLog(@"\nCalled\n"); + [self.window addSubview:expandedButtonView]; + self.expandedButtonView = nil; + self.expandedButtonView = expandedButtonView; + + if (self.panGestureRecognizer != nil) + { + self.panGestureRecognizer.delegate = self; + } + [[NSNotificationCenter defaultCenter] postNotificationName:CYRKeyboardButtonDidShowExpandedInputNotification object:self]; + isPanEnabled = YES; + return expandedButtonView; +} + +- (void)showExpandedInputView:(UILongPressGestureRecognizer *)recognizer +{ + if (recognizer.state == UIGestureRecognizerStateBegan) { + if (self.expandedButtonView == nil) { + CYRKeyboardButtonView *expandedButtonView = [[CYRKeyboardButtonView alloc] initWithKeyboardButton:self type:CYRKeyboardButtonViewTypeExpanded]; + + [self.window addSubview:expandedButtonView]; + + if (self.expandedButtonView == nil) + { + self.expandedButtonView = expandedButtonView; + } + [[NSNotificationCenter defaultCenter] postNotificationName:CYRKeyboardButtonDidShowExpandedInputNotification object:self]; + + [self hideInputView]; + } + } else if (recognizer.state == UIGestureRecognizerStateCancelled || recognizer.state == UIGestureRecognizerStateEnded) { + if (self.panGestureRecognizer.state != UIGestureRecognizerStateRecognized) { + [self handleTouchUpInside]; + } + } +} + +- (void)hideInputView +{ + [self.buttonView removeFromSuperview]; + self.buttonView = nil; + + [self setNeedsDisplay]; +} + +- (void)hideExpandedInputView +{ + if (self.expandedButtonView.type == CYRKeyboardButtonViewTypeExpanded) { + [[NSNotificationCenter defaultCenter] postNotificationName:CYRKeyboardButtonDidHideExpandedInputNotification object:self]; + } + + [self.expandedButtonView removeFromSuperview]; + self.expandedButtonView = nil; +} + +- (void)updateDisplayStyle +{ + switch (_style) { + case CYRKeyboardButtonStylePhone: + _keyCornerRadius = 4.f; + break; + + case CYRKeyboardButtonStyleTablet: + _keyCornerRadius = 6.f; + break; + + default: + break; + } + + [self setNeedsDisplay]; +} + +#pragma mark - Internal - Text Handling + +- (void)insertText:(NSString *)text +{ + BOOL shouldInsertText = YES; + + if ([self.textInput isKindOfClass:[UITextView class]]) { + // Call UITextViewDelegate methods if necessary + UITextView *textView = (UITextView *)self.textInput; + NSRange selectedRange = textView.selectedRange; + + if ([textView.delegate respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)]) { + shouldInsertText = [textView.delegate textView:textView shouldChangeTextInRange:selectedRange replacementText:text]; + } + } else if ([self.textInput isKindOfClass:[UITextField class]]) { + // Call UITextFieldDelgate methods if necessary + UITextField *textField = (UITextField *)self.textInput; + NSRange selectedRange = [self textInputSelectedRange]; + + if ([textField.delegate respondsToSelector:@selector(textField:shouldChangeCharactersInRange:replacementString:)]) { + shouldInsertText = [textField.delegate textField:textField shouldChangeCharactersInRange:selectedRange replacementString:text]; + } + } + + if (shouldInsertText == YES) { + [self.textInput insertText:text]; + + [[NSNotificationCenter defaultCenter] postNotificationName:CYRKeyboardButtonPressedNotification object:self + userInfo:@{CYRKeyboardButtonKeyPressedKey : text}]; + } +} + +- (NSRange)textInputSelectedRange +{ + UITextPosition *beginning = self.textInput.beginningOfDocument; + + UITextRange *selectedRange = self.textInput.selectedTextRange; + UITextPosition *selectionStart = selectedRange.start; + UITextPosition *selectionEnd = selectedRange.end; + + const NSInteger location = [self.textInput offsetFromPosition:beginning toPosition:selectionStart]; + const NSInteger length = [self.textInput offsetFromPosition:selectionStart toPosition:selectionEnd]; + + return NSMakeRange(location, length); +} + +#pragma mark - Internal - Configuration + +- (void)updateButtonPosition +{ + // Determine the button sposition state based on the superview padding + CGFloat leftPadding = CGRectGetMinX(self.frame); + CGFloat rightPadding = CGRectGetMaxX(self.superview.frame) - CGRectGetMaxX(self.frame); + CGFloat minimumClearance = CGRectGetWidth(self.frame) / 2 + 8; + + if (leftPadding >= minimumClearance && rightPadding >= minimumClearance) { + self.position = CYRKeyboardButtonPositionInner; + } else if (leftPadding > rightPadding) { + self.position = CYRKeyboardButtonPositionLeft; + } else { + self.position = CYRKeyboardButtonPositionRight; + } +} + +- (void)setupInputOptionsConfiguration +{ +// // if (self.inputOptions.count > 0) { +// UILongPressGestureRecognizer *longPressGestureRecognizer = +// [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(showExpandedInputView:)]; +// longPressGestureRecognizer.minimumPressDuration = 0.3; +// longPressGestureRecognizer.delegate = self; +// +// //[self.superview addGestureRecognizer:longPressGestureRecognizer]; +// self.optionsViewRecognizer = longPressGestureRecognizer; +// +// if (!self.panGestureRecognizer) +// { +// UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(_handlePanning:)]; +// panGesture.delegate = self; +// +// [self.superview addGestureRecognizer:panGesture]; +// +// +// self.panGestureRecognizer = panGesture; +// } +// + //} +} + +- (void)setupInputOptionsConfigurationWithView:(UIView*)forwordingView +{ +// if (!self.panGestureRecognizer) +// { +// panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(_handlePanning:)]; +// +// panGestureRecognizer.delegate = self; +// panGestureRecognizer.cancelsTouchesInView = NO; +// +// for (UIGestureRecognizer *gesture in forwordingView.gestureRecognizers) { +// if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]) +// { +// [forwordingView removeGestureRecognizer:gesture]; +// } +// } +// +// +// [forwordingView addGestureRecognizer:panGestureRecognizer]; +// [self.panGestureRecognizer addTarget:self action:@selector(_handlePanning:)]; +// } +// else +// { +// [self.panGestureRecognizer addTarget:self action:@selector(_handlePanning:)]; +// } + + // NSLog(@"setupInputOptionsConfigurationWithView"); +} + + +- (void)tearDownInputOptionsConfigurationWithView:(UIView*)forwordingView +{ +// if (self.panGestureRecognizer) +// { +// [forwordingView removeGestureRecognizer:self.panGestureRecognizer]; +// +// [self.panGestureRecognizer removeTarget:self action:@selector(_handlePanning:)]; +// +// //self.panGestureRecognizer = nil; +// +// NSLog(@"tearDownInputOptionsConfigurationWithView"); +// } + +} + +- (void)tearDownInputOptionsConfiguration +{ + //[self.superview removeGestureRecognizer:self.panGestureRecognizer]; +} + +#pragma mark - Touch Actions + +- (void)handleTouchDown +{ +// [[UIDevice currentDevice] playInputClick]; +// +// [self showInputView]; +} + +- (void)handleTouchUpInside +{ +// [self insertText:self.input]; +// +// [self hideInputView]; +// [self hideExpandedInputView]; +} + +- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event +{ + return self.forwordingView; +} + +- (void)_handlePanning:(UIPanGestureRecognizer *)recognizer +{ + //NSLog(@"_handlePanning"); + + if (_inputOptions.count > 0) + { + if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) { + if (self.expandedButtonView.selectedInputIndex != NSNotFound) { + NSString *inputOption = self.inputOptions[self.expandedButtonView.selectedInputIndex]; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"hideExpandViewNotification" object:nil userInfo:@{@"text":inputOption}]; + isPanEnabled = NO; + + + } + else + { + isPanEnabled = NO; + + [[NSNotificationCenter defaultCenter] postNotificationName:@"hideExpandViewNotification" object:nil]; + } + + [self tearDownInputOptionsConfigurationWithView:self.superview]; + //[self hideExpandedInputView]; + } else { + CGPoint location = [recognizer locationInView:self.superview]; + [self.expandedButtonView updateSelectedInputIndexForPoint:location]; + } + } + +} + +#pragma mark - Touch Handling + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect +{ + CGContextRef context = UIGraphicsGetCurrentContext(); + UIColor *color = self.keyColor; + + if (_style == CYRKeyboardButtonStyleTablet && self.state == UIControlStateHighlighted) { + color = self.keyHighlightedColor; + } + + UIColor *shadow = self.keyShadowColor; + CGSize shadowOffset = CGSizeMake(0.1, 1.1); + CGFloat shadowBlurRadius = 0; + + UIBezierPath *roundedRectanglePath = + [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, self.frame.size.width, self.frame.size.height - 1) cornerRadius:self.keyCornerRadius]; + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor); + [color setFill]; + [roundedRectanglePath fill]; + CGContextRestoreGState(context); +} + +@end diff --git a/Keyboard/CYRKeyboardButton/CYRKeyboardButtonView.h b/Keyboard/CYRKeyboardButton/CYRKeyboardButtonView.h new file mode 100644 index 00000000..12cfd63a --- /dev/null +++ b/Keyboard/CYRKeyboardButton/CYRKeyboardButtonView.h @@ -0,0 +1,51 @@ +// +// CYRKeyboardButtonView.h +// +// Created by Illya Busigin on 7/19/14. +// Copyright (c) 2014 Cyrillian, Inc. +// Portions Copyright (c) 2013 Nigel Timothy Barber (TurtleBezierPath) +// +// Distributed under MIT license. +// Get the latest version from here: +// +// https://github.com/illyabusigin/CYRKeyboardButton +// +// The MIT License (MIT) +// +// Copyright (c) 2014 Cyrillian, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import + +typedef NS_ENUM(NSUInteger, CYRKeyboardButtonViewType) { + CYRKeyboardButtonViewTypeInput, + CYRKeyboardButtonViewTypeExpanded +}; + +@class CYRKeyboardButton; + +@interface CYRKeyboardButtonView : UIView + +@property (nonatomic, readonly) CYRKeyboardButtonViewType type; +@property (nonatomic, readonly) NSInteger selectedInputIndex; +@property (nonatomic, readonly) UIView *inPutOptionSelectView; +- (instancetype)initWithKeyboardButton:(CYRKeyboardButton *)button type:(CYRKeyboardButtonViewType)type; +- (void)updateSelectedInputIndexForPoint:(CGPoint)point; + +@end diff --git a/Keyboard/CYRKeyboardButton/CYRKeyboardButtonView.m b/Keyboard/CYRKeyboardButton/CYRKeyboardButtonView.m new file mode 100644 index 00000000..5adf95bd --- /dev/null +++ b/Keyboard/CYRKeyboardButton/CYRKeyboardButtonView.m @@ -0,0 +1,1021 @@ +// +// CYRKeyboardButtonView.m +// +// Created by Illya Busigin on 7/19/14. +// Copyright (c) 2014 Cyrillian, Inc. +// Portions Copyright (c) 2013 Nigel Timothy Barber (TurtleBezierPath) +// +// Distributed under MIT license. +// Get the latest version from here: +// +// https://github.com/illyabusigin/CYRKeyboardButton +// +// The MIT License (MIT) +// +// Copyright (c) 2014 Cyrillian, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +#import "CYRKeyboardButtonView.h" +#import "CYRKeyboardButton.h" +#import "TurtleBezierPath.h" + +@interface CYRKeyboardButtonView () +{ + NSCharacterSet *firstRowChar; +} +@property (nonatomic, weak) CYRKeyboardButton *button; +@property (nonatomic, assign) CYRKeyboardButtonViewType type; +@property (nonatomic, assign) CYRKeyboardButtonPosition expandedPosition; +@property (nonatomic, strong) NSMutableArray *inputOptionRects; +@property (nonatomic, assign) NSInteger selectedInputIndex; + + +@end + +@implementation CYRKeyboardButtonView +@synthesize inPutOptionSelectView; +#pragma mark - UIView + +- (instancetype)initWithKeyboardButton:(CYRKeyboardButton *)button type:(CYRKeyboardButtonViewType)type; +{ + CGRect frame = [UIScreen mainScreen].bounds; + + firstRowChar = [[NSCharacterSet characterSetWithCharactersInString:@"QWERTYUIOPqwertyuiop"] invertedSet]; + + if (self.bounds.size.width>self.bounds.size.height) { + frame = CGRectMake(0, 0, CGRectGetHeight(frame), CGRectGetWidth(frame)); + } + + self = [super initWithFrame:frame]; + + if (self) { + _button = button; + _type = type; + _selectedInputIndex = 0; + + self.backgroundColor = [UIColor clearColor]; + self.userInteractionEnabled = NO; + + if (button.position != CYRKeyboardButtonPositionInner) + { + _expandedPosition = button.position; + } + else + { + // Determine the position + CGFloat leftPadding = CGRectGetMinX(button.frame); + CGFloat rightPadding = CGRectGetMaxX(button.superview.frame) - CGRectGetMaxX(button.frame); + + _expandedPosition = (leftPadding > rightPadding ? CYRKeyboardButtonPositionLeft : CYRKeyboardButtonPositionRight); + } + } + + + return self; +} + +- (void)didMoveToSuperview +{ + if (_type == CYRKeyboardButtonViewTypeExpanded) { + [self determineExpandedKeyGeometries]; + } +} + +#pragma mark - Public + +- (void)updateSelectedInputIndexForPoint:(CGPoint)point +{ + __block NSInteger selectedInputIndex = NSNotFound; + + CGRect testRect = CGRectMake(point.x, point.y, 0, 0); + + CGPoint location = [self convertRect:testRect fromView:self.button.superview].origin; + + [self.inputOptionRects enumerateObjectsUsingBlock:^(NSValue *rectValue, NSUInteger idx, BOOL *stop) { + CGRect keyRect = [rectValue CGRectValue]; + CGRect infiniteKeyRect = CGRectMake(CGRectGetMinX(keyRect), 0, CGRectGetWidth(keyRect), NSIntegerMax); + infiniteKeyRect = CGRectInset(infiniteKeyRect, -3, 0); + + if (CGRectContainsPoint(infiniteKeyRect, location)) { + selectedInputIndex = idx; + *stop = YES; + } + }]; + + + if(selectedInputIndex == NSNotFound) + { + if (self.selectedInputIndex != 0) + { + self.selectedInputIndex = 0; + //[self setNeedsDisplay]; + [self drawCustomSelectedViewFromIndex]; + } + + } + else if (self.selectedInputIndex != selectedInputIndex) { + + if (ABS(self.selectedInputIndex - selectedInputIndex) == 1) + { + self.selectedInputIndex = selectedInputIndex; + //[self setNeedsDisplay]; + [self drawCustomSelectedViewFromIndex]; + + } + + } +} + +#pragma mark - Drawing + +- (void)drawRect:(CGRect)rect +{ + switch (_type) { + case CYRKeyboardButtonViewTypeInput: + [self drawInputView:rect]; + break; + + case CYRKeyboardButtonViewTypeExpanded: + [self drawExpandedInputView:rect]; + break; + + default: + break; + } + + [self drawCustomSelectedViewFromIndex]; +} + +- (void)drawInputView:(CGRect)rect +{ + // Generate the overlay + UIBezierPath *bezierPath = [self inputViewPath]; + NSString *inputString = self.button.input; + + // Position the overlay + CGRect keyRect = [self convertRect:self.button.frame fromView:self.button.superview]; + + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Overlay path & shadow + { + //// Shadow Declarations + UIColor* shadow = [[UIColor blackColor] colorWithAlphaComponent: 0.5]; + CGSize shadowOffset = CGSizeMake(0, 0.5); + CGFloat shadowBlurRadius = 2; + + //// Rounded Rectangle Drawing + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor); + [self.button.keyColor setFill]; + [bezierPath fill]; + CGContextRestoreGState(context); + } + + // Draw the key shadow sliver + { + //// Color Declarations + UIColor *color = self.button.keyColor; + + //// Shadow Declarations + UIColor *shadow = self.button.keyShadowColor; + CGSize shadowOffset = CGSizeMake(0.1, 1.1); + CGFloat shadowBlurRadius = 0; + + //// Rounded Rectangle Drawing + UIBezierPath *roundedRectanglePath = + [UIBezierPath bezierPathWithRoundedRect:CGRectMake(keyRect.origin.x, keyRect.origin.y, keyRect.size.width, keyRect.size.height - 1) cornerRadius:4]; + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor); + [color setFill]; + [roundedRectanglePath fill]; + + CGContextRestoreGState(context); + } + + // Text drawing + { + UIColor *stringColor = self.button.keyTextColor; + + CGRect stringRect = bezierPath.bounds; + + NSMutableParagraphStyle *p = [NSMutableParagraphStyle new]; + p.alignment = NSTextAlignmentCenter; + + NSAttributedString *attributedString = [[NSAttributedString alloc] + initWithString:inputString + attributes: + @{NSFontAttributeName : [UIFont fontWithName:@"HelveticaNeue-Light" size:44], NSForegroundColorAttributeName : stringColor, NSParagraphStyleAttributeName : p}]; + [attributedString drawInRect:stringRect]; + } +} + +- (void)drawExpandedInputView:(CGRect)rect +{ + // Generate the overlay + UIBezierPath *bezierPath = [self expandedInputViewPath]; + + // Position the overlay + CGRect keyRect = [self convertRect:self.button.frame fromView:self.button.superview]; + + CGContextRef context = UIGraphicsGetCurrentContext(); + + // Overlay path & shadow + { + CGFloat shadowAlpha = 0; + CGSize shadowOffset; + + switch ([UIDevice currentDevice].userInterfaceIdiom) { + case UIUserInterfaceIdiomPhone: + shadowAlpha = 0.5; + shadowOffset = CGSizeMake(0, 0.5); + break; + + case UIUserInterfaceIdiomPad: + shadowAlpha = 0.25; + shadowOffset = CGSizeZero; + + break; + + default: + break; + } + + //// Shadow Declarations + UIColor* shadow = [[UIColor blackColor] colorWithAlphaComponent: shadowAlpha]; + CGFloat shadowBlurRadius = 2; + + //// Rounded Rectangle Drawing + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor); + [self.button.keyColor setFill]; + [bezierPath fill]; + CGContextRestoreGState(context); + } + + // Draw the key shadow sliver + if (self.button.style == CYRKeyboardButtonStylePhone) { + UIColor *color = self.button.keyColor; + + //// Shadow Declarations + UIColor *shadow = self.button.keyShadowColor; + CGSize shadowOffset = CGSizeMake(0.1, 1.1); + CGFloat shadowBlurRadius = 0; + + //// Rounded Rectangle Drawing + UIBezierPath *roundedRectanglePath = + [UIBezierPath bezierPathWithRoundedRect:CGRectMake(keyRect.origin.x, keyRect.origin.y, keyRect.size.width, keyRect.size.height - 1) cornerRadius:4]; + CGContextSaveGState(context); + CGContextSetShadowWithColor(context, shadowOffset, shadowBlurRadius, shadow.CGColor); + [color setFill]; + [roundedRectanglePath fill]; + + CGContextRestoreGState(context); + } + + [self drawExpandedInputViewOptions]; +} + +- (void)drawExpandedInputViewOptions +{ + + CGContextRef context = UIGraphicsGetCurrentContext(); + CGContextSetShadowWithColor(context, CGSizeZero, 0, [[UIColor clearColor] CGColor]); + CGContextSaveGState(context); + + NSArray *inputOptions = self.button.inputOptions; + + [inputOptions enumerateObjectsUsingBlock:^(NSString *optionString, NSUInteger idx, BOOL *stop) { + CGRect optionRect = [self.inputOptionRects[idx] CGRectValue]; + + UIFont *fontt ; + + if (optionString.length > 1) + { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + fontt = self.button.inputOptionsFont; + } + else + { + fontt = [UIFont systemFontOfSize:18]; + if (![self isLandScapeOrientation]) + { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + optionRect.origin.x = optionRect.origin.x + 10; + } + else + { + optionRect.origin.x = optionRect.origin.x - 10; + } + + + } + else + { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + //optionRect.origin.x = optionRect.origin.x - 12; + } + else + { + optionRect.origin.x = optionRect.origin.x + 12; + } + + } + } + + + } + else + { + fontt = self.button.inputOptionsFont; + } + + + BOOL selected = (idx == self.selectedInputIndex); + + if (selected) { + // Draw selection background +// UIBezierPath *roundedRectanglePath = [UIBezierPath bezierPathWithRoundedRect:optionRect cornerRadius:4]; +// +// [[UIColor grayColor] setFill]; +// [roundedRectanglePath fill]; + } + + // Draw the text + //UIColor *stringColor = (selected ? [UIColor whiteColor] : self.button.keyTextColor); + UIColor *stringColor = self.button.keyTextColor; + CGSize stringSize = [optionString sizeWithAttributes:@{NSFontAttributeName : self.button.inputOptionsFont}]; + CGRect stringRect = CGRectMake( + CGRectGetMidX(optionRect) - stringSize.width / 2, CGRectGetMidY(optionRect) - stringSize.height / 2, stringSize.width, stringSize.height); + + NSMutableParagraphStyle *p = [NSMutableParagraphStyle new]; + p.alignment = NSTextAlignmentCenter; + + + NSAttributedString *attributedString = [[NSAttributedString alloc] + initWithString:optionString + attributes: + @{NSFontAttributeName : fontt, NSForegroundColorAttributeName : stringColor, NSParagraphStyleAttributeName : p}]; + [attributedString drawInRect:stringRect]; + }]; + + CGContextRestoreGState(context); + + +} + + +-(void)drawCustomSelectedViewFromIndex +{ + CGRect optionRect = [self.inputOptionRects[self.selectedInputIndex] CGRectValue]; + + NSString *optionString = self.button.inputOptions[0]; + if (optionString.length > 1) + { + if (![self isLandScapeOrientation]) + { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + optionRect.origin.x = optionRect.origin.x ; + } + else + { + optionRect.origin.x = optionRect.origin.x - 10; + } + + } + else + { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + //optionRect.origin.x = optionRect.origin.x - 12; + } + else + { + optionRect.origin.x = optionRect.origin.x + 12; + } + + } + } + + + if (inPutOptionSelectView == nil) + { + inPutOptionSelectView = [[UIView alloc]initWithFrame:optionRect]; + inPutOptionSelectView.backgroundColor = [UIColor clearColor]; + + inPutOptionSelectView.layer.cornerRadius = 4; + inPutOptionSelectView.layer.borderColor = [[UIColor blueColor] colorWithAlphaComponent:0.5].CGColor;//[UIColor blueColor].CGColor; + inPutOptionSelectView.layer.borderWidth = 1; + + [self addSubview:inPutOptionSelectView]; + + } + inPutOptionSelectView.frame = optionRect; +} + +#pragma mark - Internal + +- (UIBezierPath *)inputViewPath +{ + CGRect keyRect = [self convertRect:self.button.frame fromView:self.button.superview]; + + UIEdgeInsets insets = UIEdgeInsetsMake(7, 13, 7, 13); + CGFloat upperWidth = CGRectGetWidth(_button.frame) + insets.left + insets.right; + CGFloat lowerWidth = CGRectGetWidth(_button.frame); + CGFloat majorRadius = 10.f; + CGFloat minorRadius = 4.f; + + TurtleBezierPath *path = [TurtleBezierPath new]; + [path home]; + path.lineWidth = 0; + path.lineCapStyle = kCGLineCapRound; + + switch (self.button.position) { + case CYRKeyboardButtonPositionInner: + { + if ([self.button.input rangeOfCharacterFromSet:firstRowChar].location == NSNotFound) + { + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + + [path forward:(CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom) - 4]; // #4 right big + + [path rightArc:majorRadius turn:48]; // #5 + [path forward:8.5f]; + [path leftArc:majorRadius turn:48]; // #6 + + [path forward:CGRectGetHeight(keyRect) - 8.5f + 1 - 10];//lower small left + + [path rightArc:minorRadius turn:90]; + [path forward:lowerWidth - 2 * minorRadius]; // lowerWidth - 2 * minorRadius + 0.5f + [path rightArc:minorRadius turn:90]; + + [path forward:(CGRectGetHeight(keyRect) - 2 * minorRadius) - 10];//lower small right + + [path leftArc:majorRadius turn:48]; + [path forward:8.5f]; + [path rightArc:majorRadius turn:48]; + + + CGFloat offsetX = 0, offsetY = 0; + CGRect pathBoundingBox = path.bounds; + + offsetX = CGRectGetMidX(keyRect) - CGRectGetMidX(path.bounds); + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(pathBoundingBox) + 10; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + else + { + + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom]; // #4 right big + [path rightArc:majorRadius turn:48]; // #5 + [path forward:8.5f]; + [path leftArc:majorRadius turn:48]; // #6 + [path forward:CGRectGetHeight(keyRect) - 8.5f + 1]; + [path rightArc:minorRadius turn:90]; + [path forward:lowerWidth - 2 * minorRadius]; // lowerWidth - 2 * minorRadius + 0.5f + [path rightArc:minorRadius turn:90]; + [path forward:CGRectGetHeight(keyRect) - 2 * minorRadius]; + [path leftArc:majorRadius turn:48]; + [path forward:8.5f]; + [path rightArc:majorRadius turn:48]; + + CGFloat offsetX = 0, offsetY = 0; + CGRect pathBoundingBox = path.bounds; + + offsetX = CGRectGetMidX(keyRect) - CGRectGetMidX(path.bounds); + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(pathBoundingBox) + 10; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + + } + + } + break; + + case CYRKeyboardButtonPositionLeft: + { + if ([self.button.input rangeOfCharacterFromSet:firstRowChar].location == NSNotFound) + { + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:(CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom)-5]; // #4 right big + [path rightArc:majorRadius turn:45]; // #5 + [path forward:28]; // 6 + [path leftArc:majorRadius turn:45]; // #7 + [path forward:(CGRectGetHeight(keyRect) - 26 + (insets.left + insets.right) / 4) - 10]; // #8 + [path rightArc:minorRadius turn:90]; // 9 + [path forward:path.currentPoint.x - minorRadius]; // 10 + [path rightArc:minorRadius turn:90]; // 11 + + + CGFloat offsetX = 0, offsetY = 0; + CGRect pathBoundingBox = path.bounds; + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(path.bounds); + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(pathBoundingBox) - CGRectGetMinY(path.bounds); + + [path applyTransform:CGAffineTransformTranslate(CGAffineTransformMakeScale(-1, 1), -offsetX - CGRectGetWidth(path.bounds), offsetY)]; + } + else + { + + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom]; // #4 right big + [path rightArc:majorRadius turn:45]; // #5 + [path forward:28]; // 6 + [path leftArc:majorRadius turn:45]; // #7 + [path forward:CGRectGetHeight(keyRect) - 26 + (insets.left + insets.right) / 4]; // #8 + [path rightArc:minorRadius turn:90]; // 9 + [path forward:path.currentPoint.x - minorRadius]; // 10 + [path rightArc:minorRadius turn:90]; // 11 + + + CGFloat offsetX = 0, offsetY = 0; + CGRect pathBoundingBox = path.bounds; + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(path.bounds); + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(pathBoundingBox) - CGRectGetMinY(path.bounds); + + [path applyTransform:CGAffineTransformTranslate(CGAffineTransformMakeScale(-1, 1), -offsetX - CGRectGetWidth(path.bounds), offsetY)]; + } + + } + break; + + case CYRKeyboardButtonPositionRight: + { + if ([self.button.input rangeOfCharacterFromSet:firstRowChar].location == NSNotFound) + { + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:(CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom) - 5]; // #4 right big + [path rightArc:majorRadius turn:45]; // #5 + [path forward:28]; // 6 + [path leftArc:majorRadius turn:45]; // #7 + [path forward:(CGRectGetHeight(keyRect) - 26 + (insets.left + insets.right) / 4) - 10]; // #8 + [path rightArc:minorRadius turn:90]; // 9 + [path forward:path.currentPoint.x - minorRadius]; // 10 + [path rightArc:minorRadius turn:90]; // 11 + + CGFloat offsetX = 0, offsetY = 0; + CGRect pathBoundingBox = path.bounds; + + offsetX = CGRectGetMinX(keyRect); + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(pathBoundingBox) - CGRectGetMinY(path.bounds); + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + else + { + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom]; // #4 right big + [path rightArc:majorRadius turn:45]; // #5 + [path forward:28]; // 6 + [path leftArc:majorRadius turn:45]; // #7 + [path forward:CGRectGetHeight(keyRect) - 26 + (insets.left + insets.right) / 4]; // #8 + [path rightArc:minorRadius turn:90]; // 9 + [path forward:path.currentPoint.x - minorRadius]; // 10 + [path rightArc:minorRadius turn:90]; // 11 + + CGFloat offsetX = 0, offsetY = 0; + CGRect pathBoundingBox = path.bounds; + + offsetX = CGRectGetMinX(keyRect); + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(pathBoundingBox) - CGRectGetMinY(path.bounds); + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + + + } + break; + + default: + break; + } + + return path; +} + +- (UIBezierPath *)expandedInputViewPath +{ + CGRect keyRect = [self convertRect:self.button.frame fromView:self.button.superview]; + + NSString *optionChar = self.button.inputOptions[0]; + + float widthOneOption = 0.0;//= CGRectGetWidth(keyRect) * optionChar.length; + + for (NSString *strOption in self.button.inputOptions) + { + if (strOption.length > 1) + { + CGSize stringSize = [strOption sizeWithAttributes:@{NSFontAttributeName : self.button.inputOptionsFont}]; + widthOneOption = widthOneOption + stringSize.width; + + } + } + + UIEdgeInsets insets = UIEdgeInsetsMake(7, 13, 7, 13); + CGFloat margin = 7.f; + + CGFloat upperWidth; + + if (optionChar.length > 1) + { + upperWidth = insets.left + insets.right + widthOneOption + margin * (self.button.inputOptions.count - 1) - margin/2; + } + else + { + upperWidth = insets.left + insets.right + self.button.inputOptions.count * CGRectGetWidth(keyRect) + margin * (self.button.inputOptions.count - 1) - margin/2; + } + + + + CGFloat lowerWidth = CGRectGetWidth(_button.frame); + CGFloat majorRadius = 10.f; + CGFloat minorRadius = 4.f; + + TurtleBezierPath *path = [TurtleBezierPath new]; + [path home]; + path.lineWidth = 0; + path.lineCapStyle = kCGLineCapRound; + + CGFloat offsetX = 0, offsetY = 0; + + switch (_expandedPosition) { + case CYRKeyboardButtonPositionRight: + { + switch (self.button.style) { + case CYRKeyboardButtonStylePhone: + { + + if ([self.button.input rangeOfCharacterFromSet:firstRowChar].location == NSNotFound) + { + [path rightArc:majorRadius turn:90]; // #1 + [path forward:(upperWidth - 2 * majorRadius) - 28]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + + [path forward:(CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom - 3) - 5]; // #4 right big + + [path rightArc:majorRadius turn:90]; // #5 + [path forward:path.currentPoint.x - (CGRectGetWidth(keyRect) + 2 * majorRadius + 3)]; + [path leftArc:majorRadius turn:90]; // #6 + + [path forward:(CGRectGetHeight(keyRect) - minorRadius) - 20]; + + [path rightArc:minorRadius turn:90]; + [path forward:lowerWidth - 2 * minorRadius]; // lowerWidth - 2 * minorRadius + 0.5f + [path rightArc:minorRadius turn:90]; + + [path forward:(CGRectGetHeight(keyRect) - 2 * minorRadius) - 20]; + + [path leftArc:majorRadius turn:48]; + [path forward:8.5f]; + [path rightArc:majorRadius turn:48]; + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(keyRect) - insets.left; + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(path.bounds) + 10; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + else + { + + + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom - 3]; // #4 right big + [path rightArc:majorRadius turn:90]; // #5 + [path forward:path.currentPoint.x - (CGRectGetWidth(keyRect) + 2 * majorRadius + 3)]; + [path leftArc:majorRadius turn:90]; // #6 + [path forward:CGRectGetHeight(keyRect) - minorRadius]; + [path rightArc:minorRadius turn:90]; + [path forward:lowerWidth - 2 * minorRadius]; // lowerWidth - 2 * minorRadius + 0.5f + [path rightArc:minorRadius turn:90]; + [path forward:CGRectGetHeight(keyRect) - 2 * minorRadius]; + [path leftArc:majorRadius turn:48]; + [path forward:8.5f]; + [path rightArc:majorRadius turn:48]; + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(keyRect) - insets.left; + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(path.bounds) + 10; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + + + + + } + break; + + case CYRKeyboardButtonStyleTablet: + { + CGRect firstRect = [self.inputOptionRects[0] CGRectValue]; + + path = (id)[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, CGRectGetWidth(firstRect) * self.button.inputOptions.count + 12, CGRectGetHeight(firstRect) + 12) + cornerRadius:6]; + + offsetX = CGRectGetMinX(keyRect); + offsetY = CGRectGetMinY(firstRect) - 6; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + + } + break; + + default: + break; + } + + + } + break; + + case CYRKeyboardButtonPositionLeft: + { + switch (self.button.style) { + case CYRKeyboardButtonStylePhone: + { + + if ([self.button.input rangeOfCharacterFromSet:firstRowChar].location == NSNotFound) + { + [path rightArc:majorRadius turn:90]; // #1 + [path forward:(upperWidth - 2 * majorRadius) - 20]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + + [path forward:(CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom - 3) - 5]; // #4 right big + + [path rightArc:majorRadius turn:48]; + [path forward:8.5f]; + [path leftArc:majorRadius turn:48]; + + [path forward:(CGRectGetHeight(keyRect) - minorRadius) - 20]; + + [path rightArc:minorRadius turn:90]; + [path forward:lowerWidth - 2 * minorRadius]; // lowerWidth - 2 * minorRadius + 0.5f + [path rightArc:minorRadius turn:90]; + + [path forward:(CGRectGetHeight(keyRect) - 2 * minorRadius) - 20]; + + [path leftArc:majorRadius turn:90]; // #5 + [path forward:path.currentPoint.x - majorRadius]; + [path rightArc:majorRadius turn:90]; // #6 + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(path.bounds) + insets.left; + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(path.bounds) + 10; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + else + { + + + [path rightArc:majorRadius turn:90]; // #1 + [path forward:upperWidth - 2 * majorRadius]; // #2 top + [path rightArc:majorRadius turn:90]; // #3 + [path forward:CGRectGetHeight(keyRect) - 2 * majorRadius + insets.top + insets.bottom - 3]; // #4 right big + + [path rightArc:majorRadius turn:48]; + [path forward:8.5f]; + [path leftArc:majorRadius turn:48]; + + [path forward:CGRectGetHeight(keyRect) - minorRadius]; + [path rightArc:minorRadius turn:90]; + [path forward:lowerWidth - 2 * minorRadius]; // lowerWidth - 2 * minorRadius + 0.5f + [path rightArc:minorRadius turn:90]; + [path forward:CGRectGetHeight(keyRect) - 2 * minorRadius]; + + [path leftArc:majorRadius turn:90]; // #5 + [path forward:path.currentPoint.x - majorRadius]; + [path rightArc:majorRadius turn:90]; // #6 + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(path.bounds) + insets.left; + offsetY = CGRectGetMaxY(keyRect) - CGRectGetHeight(path.bounds) + 10; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + + } + + + } + break; + + case CYRKeyboardButtonStyleTablet: + { + CGRect firstRect = [self.inputOptionRects[0] CGRectValue]; + + path = (id)[UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, CGRectGetWidth(firstRect) * self.button.inputOptions.count + 12, CGRectGetHeight(firstRect) + 12) + cornerRadius:6]; + + offsetX = CGRectGetMaxX(keyRect) - CGRectGetWidth(path.bounds); + offsetY = CGRectGetMinY(firstRect) - 6; + + [path applyTransform:CGAffineTransformMakeTranslation(offsetX, offsetY)]; + } + break; + + default: + break; + } + } + break; + + default: + break; + } + + return path; +} + +- (void)determineExpandedKeyGeometries +{ + CGRect keyRect = [self convertRect:self.button.frame fromView:self.button.superview]; + + if ([self.button.input rangeOfCharacterFromSet:firstRowChar].location == NSNotFound) + { + keyRect = CGRectMake(keyRect.origin.x, keyRect.origin.y + 22, keyRect.size.width -2 , keyRect.size.height ); + } + + + NSString *optionChar = self.button.inputOptions[0]; + +// CGSize stringSize = [optionChar sizeWithAttributes:@{NSFontAttributeName : self.button.inputOptionsFont}]; + + CGSize stringSize = [optionChar sizeWithAttributes:@{NSFontAttributeName : self.button.inputOptionsFont}]; + + if (optionChar.length > 1) + { + keyRect.size.width = stringSize.width - 5; + + if ([self isLandScapeOrientation]) + { + int screenWidth = [UIScreen mainScreen].bounds.size.width; + + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + NSLog(@"%f",keyRect.origin.x); + + if (keyRect.origin.x > 850) + { + keyRect.origin.x = keyRect.origin.x - 35; + } + keyRect.size.width = stringSize.width + 45; + } + else + { + if (screenWidth == 667)//iphone6 + { + if(keyRect.origin.x == 519) + { + keyRect.origin.x = keyRect.origin.x + 8; // url + } + else + { + keyRect.origin.x = keyRect.origin.x - 10; + } + + + } + else if (screenWidth == 736)//iphone6p + { + if(keyRect.origin.x <= 577) + { + keyRect.origin.x = keyRect.origin.x + 11; // url + } + else + { + keyRect.origin.x = keyRect.origin.x - 5; + } + //keyRect.origin.x = keyRect.origin.x - 5; + } + else if(screenWidth == 568) // iPhone 5 + { + if(keyRect.origin.x >= 450) + { + keyRect.origin.x = keyRect.origin.x - 15; + } + else + { + keyRect.origin.x = keyRect.origin.x - 5; + } + + } + else if (screenWidth == 480)//iphone4 + { + keyRect.origin.x = keyRect.origin.x - 18; + } + } + } + else + { + if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) + { + + if(keyRect.origin.x < 240 ) + { + keyRect.origin.x = keyRect.origin.x - 45; + } + else if (keyRect.origin.x > 628) + { + keyRect.origin.x = keyRect.origin.x - 25; + } + + keyRect.size.width = stringSize.width + 20; + } + } + + } + + __block NSMutableArray *inputOptionRects = [NSMutableArray arrayWithCapacity:self.button.inputOptions.count]; + + CGFloat offset = 0; + CGFloat spacing = 0; + + __block CGRect optionRect = CGRectZero; + + switch (self.button.style) { + case CYRKeyboardButtonStylePhone: + offset = CGRectGetWidth(keyRect); + spacing = 6;//6 + optionRect = CGRectOffset(CGRectInset(keyRect, 0, 0.5), 0, -(CGRectGetHeight(keyRect) + 15)); + break; + + case CYRKeyboardButtonStyleTablet: + spacing = 0; + optionRect = CGRectOffset(CGRectInset(keyRect, 6, 6), 0, -(CGRectGetHeight(keyRect) + 3)); + offset = CGRectGetWidth(optionRect); + break; + + default: + break; + } + + [self.button.inputOptions enumerateObjectsUsingBlock:^(NSString *option, NSUInteger idx, BOOL *stop) { + + + [inputOptionRects addObject:[NSValue valueWithCGRect:optionRect]]; + + + // Offset the option rect + switch (_expandedPosition) { + case CYRKeyboardButtonPositionRight: + optionRect = CGRectOffset(optionRect, +(offset + spacing), 0); + break; + + case CYRKeyboardButtonPositionLeft: + optionRect = CGRectOffset(optionRect, -(offset + spacing), 0); + break; + + default: + break; + } + }]; + + self.inputOptionRects = inputOptionRects; +} + +-(BOOL)isLandScapeOrientation +{ + if([[UIScreen mainScreen] bounds].size.width < [[UIScreen mainScreen] bounds].size.height) + { + return NO; + } + + return YES; +} + +@end diff --git a/Keyboard/CYRKeyboardButton/TurtleBezierPath.h b/Keyboard/CYRKeyboardButton/TurtleBezierPath.h new file mode 100755 index 00000000..99402cd5 --- /dev/null +++ b/Keyboard/CYRKeyboardButton/TurtleBezierPath.h @@ -0,0 +1,29 @@ +// +// TurtleBezierPath.h +// TurtleBezierPath demo +// +// Created by Nigel Barber on 09/12/2013. +// Copyright (c) 2013 Nigel Barber. All rights reserved. +// + +#import + +@interface TurtleBezierPath : UIBezierPath + +@property( nonatomic, assign ) CGFloat bearing; +@property( nonatomic, assign ) BOOL penUp; + +-(CGRect)boundsWithStroke; +-(CGRect)boundsForView; + +-(void)home; +-(void)forward:(CGFloat)distance; +-(void)turn:(CGFloat)angle; +-(void)leftArc:(CGFloat)radius turn:(CGFloat)angle; +-(void)rightArc:(CGFloat)radius turn:(CGFloat)angle; +-(void)down; +-(void)up; + +-(void)centreInBounds:(CGRect)bounds; + +@end diff --git a/Keyboard/CYRKeyboardButton/TurtleBezierPath.m b/Keyboard/CYRKeyboardButton/TurtleBezierPath.m new file mode 100755 index 00000000..acdb11b9 --- /dev/null +++ b/Keyboard/CYRKeyboardButton/TurtleBezierPath.m @@ -0,0 +1,176 @@ +// +// TurtleBezierPath.m +// TurtleBezierPath demo +// +// Created by Nigel Barber on 09/12/2013. +// Copyright (c) 2013 Nigel Barber. All rights reserved. +// + +#import "TurtleBezierPath.h" + +@implementation TurtleBezierPath + + +#pragma mark - NSCoding + +-(void)encodeWithCoder:(NSCoder *)aCoder +{ + [ super encodeWithCoder:aCoder ]; + + [ aCoder encodeFloat:self.bearing forKey:@"bearing" ]; + [ aCoder encodeBool:self.penUp forKey:@"penUp" ]; +} + +- (id)initWithCoder:(NSCoder *)aDecoder +{ + if( self = [ super initWithCoder:aDecoder ]) + { + self.bearing = [ aDecoder decodeFloatForKey:@"bearing" ]; + self.penUp = [ aDecoder decodeBoolForKey:@"penUp" ]; + } + + return self; +} + + +#pragma mark - NSCopying + +-(id)copyWithZone:(NSZone *)zone +{ + TurtleBezierPath *clone = [[ TurtleBezierPath allocWithZone:zone ] init ]; + clone.CGPath = self.CGPath; + clone.lineCapStyle = self.lineCapStyle; + clone.lineJoinStyle = self.lineJoinStyle; + clone.lineWidth = self.lineWidth; + clone.miterLimit = self.miterLimit; + clone.flatness = self.flatness; + clone.usesEvenOddFillRule = self.usesEvenOddFillRule; + + CGFloat phase; + NSInteger count; + [ self getLineDash:nil count:&count phase:&phase ]; + CGFloat *lineDash = malloc( count * sizeof( CGFloat )); + [ self getLineDash:lineDash count:&count phase:&phase ]; + [ clone setLineDash:lineDash count:count phase:phase ]; + free( lineDash ); + + clone.bearing = self.bearing; + clone.penUp = self.penUp; + + return clone; +} + + +#pragma mark - Private methods + +-(void)arc:(CGFloat)radius turn:(CGFloat)angle clockwise:(BOOL)clockwise +{ + CGFloat radiusTurn = ( clockwise ) ? 90.0f : -90.0f; + CGFloat cgAngleBias = ( clockwise ) ? 180.0f : 0.0f; + angle = ( clockwise ) ? angle : -angle; + + CGPoint centre = [ self toCartesian:radius bearing:self.bearing + radiusTurn origin:self.currentPoint ]; + + CGFloat cgStartAngle = cgAngleBias + self.bearing; + CGFloat cgEndAngle = cgAngleBias + ( self.bearing + angle ); + + self.bearing += angle; + CGPoint endPoint = [ self toCartesian:radius bearing:( self.bearing -radiusTurn ) origin:centre ]; + + if( self.penUp ) + { + [ self moveToPoint:endPoint ]; + } + else + { + [ self addArcWithCenter:centre radius:radius startAngle:radians( cgStartAngle ) endAngle:radians( cgEndAngle ) clockwise:clockwise ]; + } +} + + +#pragma mark - Public methods + +-(CGRect)boundsWithStroke +{ + return CGRectIntegral( CGRectInset( self.bounds, -self.lineWidth * 0.5f, -self.lineWidth * 0.5f )); +} + +-(CGRect)boundsForView +{ + CGRect bounds = self.boundsWithStroke; + CGFloat maxWidth = MAX( fabs( CGRectGetMinX( bounds )), fabs( CGRectGetMaxX( bounds ))); + CGFloat maxHeight = MAX( fabs( CGRectGetMinY( bounds )), fabs( CGRectGetMaxY( bounds ))); + + return CGRectMake( 0.0f, 0.0f, maxWidth * 2.0f, maxHeight * 2.0f ); +} + +-(BOOL)isEqual:(TurtleBezierPath *)aPath +{ + return [[ NSKeyedArchiver archivedDataWithRootObject:self ] isEqualToData:[ NSKeyedArchiver archivedDataWithRootObject:aPath ]]; +} + +-(void)home +{ + [ self moveToPoint:CGPointZero ]; + self.bearing = 0.0f; +} + +-(void)forward:(CGFloat)distance +{ + CGPoint endPoint = [ self toCartesian:distance bearing:self.bearing origin:self.currentPoint ]; + + if( self.penUp ) + { + [ self moveToPoint:endPoint ]; + } + else + { + [ self addLineToPoint:endPoint ]; + } +} + +-(void)turn:(CGFloat)angle +{ + self.bearing += angle; +} + +-(void)leftArc:(CGFloat)radius turn:(CGFloat)angle +{ + [ self arc:radius turn:angle clockwise:NO ]; +} + +-(void)rightArc:(CGFloat)radius turn:(CGFloat)angle +{ + [ self arc:radius turn:angle clockwise:YES ]; +} + +-(void)down +{ + self.penUp = NO; +} + +-(void)up +{ + self.penUp = YES; +} + +-(void)centreInBounds:(CGRect)bounds +{ + [ self applyTransform:CGAffineTransformMakeTranslation( bounds.size.width / 2.0f, bounds.size.height / 2.0f )]; +} + +#pragma mark - Maths + +static inline CGFloat radians (CGFloat degrees) {return degrees * M_PI / 180.0;} + +-(CGPoint)toCartesian:(CGFloat)radius bearing:(CGFloat)bearing origin:(CGPoint)origin +{ + CGFloat bearingInRadians = radians( bearing ); + + CGPoint vector = CGPointMake( radius * sinf( bearingInRadians ), -radius * cosf( bearingInRadians )); + + return CGPointMake( origin.x + vector.x, origin.y + vector.y ); +} + + +@end diff --git a/Keyboard/Catboard.swift b/Keyboard/Catboard.swift index ce1b9262..8eeebef3 100644 --- a/Keyboard/Catboard.swift +++ b/Keyboard/Catboard.swift @@ -87,7 +87,7 @@ class Catboard: KeyboardViewController { for rowKeys in page.rows { for key in rowKeys { if let keyView = self.layout!.viewForKey(key) { - keyView.addTarget(self, action: "takeScreenshotDelay", forControlEvents: .TouchDown) + keyView.addTarget(self, action: #selector(Catboard.takeScreenshotDelay), forControlEvents: .TouchDown) } } } @@ -100,7 +100,7 @@ class Catboard: KeyboardViewController { } func takeScreenshotDelay() { - NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: Selector("takeScreenshot"), userInfo: nil, repeats: false) + NSTimer.scheduledTimerWithTimeInterval(0.1, target: self, selector: #selector(Catboard.takeScreenshot), userInfo: nil, repeats: false) } func takeScreenshot() { @@ -112,11 +112,13 @@ class Catboard: KeyboardViewController { let rect = self.view.bounds UIGraphicsBeginImageContextWithOptions(rect.size, true, 0) - var context = UIGraphicsGetCurrentContext() + var _ = UIGraphicsGetCurrentContext() self.view.drawViewHierarchyInRect(self.view.bounds, afterScreenUpdates: true) let capturedImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() - let name = (self.interfaceOrientation.isPortrait ? "Screenshot-Portrait" : "Screenshot-Landscape") + let isPortrait = UIScreen.mainScreen().nativeBounds.size.width < UIScreen.mainScreen().nativeBounds.size.height + + let name = (isPortrait ? "Screenshot-Portrait" : "Screenshot-Landscape") let imagePath = "/Users/archagon/Documents/Programming/OSX/RussianPhoneticKeyboard/External/tasty-imitation-keyboard/\(name).png" if let pngRep = UIImagePNGRepresentation(capturedImage) { diff --git a/Keyboard/CatboardBanner.swift b/Keyboard/CatboardBanner.swift index f9c3be83..2a275743 100644 --- a/Keyboard/CatboardBanner.swift +++ b/Keyboard/CatboardBanner.swift @@ -17,24 +17,24 @@ class CatboardBanner: ExtraView { var catSwitch: UISwitch = UISwitch() var catLabel: UILabel = UILabel() - + + var touchToView: [UITouch:UIView] + + var isAllowFullAccess : Bool = false + required init(globalColors: GlobalColors.Type?, darkMode: Bool, solidColorMode: Bool) { + self.touchToView = [:] + super.init(globalColors: globalColors, darkMode: darkMode, solidColorMode: solidColorMode) - - self.addSubview(self.catSwitch) - self.addSubview(self.catLabel) - - self.catSwitch.on = NSUserDefaults.standardUserDefaults().boolForKey(kCatTypeEnabled) - self.catSwitch.transform = CGAffineTransformMakeScale(0.75, 0.75) - self.catSwitch.addTarget(self, action: Selector("respondToSwitch"), forControlEvents: UIControlEvents.ValueChanged) - + self.updateAppearance() } + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + override func setNeedsLayout() { super.setNeedsLayout() } @@ -42,9 +42,6 @@ class CatboardBanner: ExtraView { override func layoutSubviews() { super.layoutSubviews() - self.catSwitch.center = self.center - self.catLabel.center = self.center - self.catLabel.frame.origin = CGPointMake(self.catSwitch.frame.origin.x + self.catSwitch.frame.width + 8, self.catLabel.frame.origin.y) } func respondToSwitch() { @@ -53,15 +50,414 @@ class CatboardBanner: ExtraView { } func updateAppearance() { - if self.catSwitch.on { - self.catLabel.text = "😺" - self.catLabel.alpha = 1 + + isAllowFullAccess = isOpenAccessGranted() + + btn1 = UIButton(type: .Custom) + btn1.exclusiveTouch = true + btn1.titleLabel!.minimumScaleFactor = 0.6 + btn1 .setTitle("The", forState: UIControlState.Normal) + btn1.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + btn1.titleLabel?.font = UIFont.systemFontOfSize(18) + btn1.setTitleColor(UIColor.whiteColor(), forState: .Normal) + btn1.translatesAutoresizingMaskIntoConstraints = false + btn1.titleLabel!.adjustsFontSizeToFitWidth = true + + btn2 = UIButton(type: .Custom) + btn2.exclusiveTouch = true + btn2.titleLabel!.minimumScaleFactor = 0.6 + btn2 .setTitle("I", forState: UIControlState.Normal) + btn2.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + btn2.titleLabel?.font = UIFont.systemFontOfSize(18) + btn2.setTitleColor(UIColor.whiteColor(), forState: .Normal) + btn2.translatesAutoresizingMaskIntoConstraints = false + btn2.titleLabel!.adjustsFontSizeToFitWidth = true + + btn3 = UIButton(type: .Custom) + btn3.exclusiveTouch = true + btn3.titleLabel!.minimumScaleFactor = 0.6 + btn3 .setTitle("What", forState: UIControlState.Normal) + btn3.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + btn3.titleLabel?.font = UIFont.systemFontOfSize(18) + btn3.setTitleColor(UIColor.whiteColor(), forState: .Normal) + btn3.translatesAutoresizingMaskIntoConstraints = false + btn3.titleLabel!.adjustsFontSizeToFitWidth = true + + btn4 = UIButton(type: .Custom) + btn4.exclusiveTouch = true + btn4.titleLabel!.minimumScaleFactor = 0.6 + btn4 .setTitle("Enable Allow Full Access", forState: UIControlState.Normal) + btn4.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + btn4.titleLabel?.font = UIFont.systemFontOfSize(18) + btn4.setTitleColor(UIColor.whiteColor(), forState: .Normal) + btn4.translatesAutoresizingMaskIntoConstraints = false + btn4.titleLabel!.adjustsFontSizeToFitWidth = true + + if(isAllowFullAccess == true) + { + self.addSubview(self.btn1) + self.addSubview(self.btn2) + self.addSubview(self.btn3) } - else { - self.catLabel.text = "🐱" - self.catLabel.alpha = 0.5 + else + { + //btn4.frame = (CGRectMake(0, 0, 430, 30)) + self.addSubview(self.btn4) } + + addConstraintsToButtons() + } + + + func isOpenAccessGranted() -> Bool { + + return (UIPasteboard.generalPasteboard().isKindOfClass(UIPasteboard)) - self.catLabel.sizeToFit() +// let fm = NSFileManager.defaultManager() +// let containerPath = fm.containerURLForSecurityApplicationGroupIdentifier( +// "group.com.spanglish.www")?.path +// var error: NSError? +// fm.contentsOfDirectoryAtPath(containerPath!, error: &error) +// if (error != nil) { +// NSLog("Full Access: Off") +// return false +// } +// NSLog("Full Access: On"); +// return true } + + override func drawRect(rect: CGRect) {} + + override func hitTest(point: CGPoint, withEvent event: UIEvent!) -> UIView? { + + if self.hidden || self.alpha == 0 || !self.userInteractionEnabled { + return nil + } + else + { + return (CGRectContainsPoint(self.bounds, point) ? self : nil) + + } +// if self.frame.size.height == 30 +// { +// return (CGRectContainsPoint(self.bounds, point) ? self : nil) +// } +// else +// { +// return nil +// } +// + + } + + + func addConstraintsToButtons() + { + + if(isAllowFullAccess == true) + { + var buttons = [btn1,btn2,btn3] + + for (index, button) in buttons.enumerate() { + + let topConstraint = NSLayoutConstraint(item: button, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0) + + let bottomConstraint = NSLayoutConstraint(item: button, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0) + + var rightConstraint : NSLayoutConstraint! + + if index == 2 + { + rightConstraint = NSLayoutConstraint(item: button, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1.0, constant: 0) + self.addConstraint(rightConstraint) + } + + var leftConstraint : NSLayoutConstraint! + + if index == 0 + { + leftConstraint = NSLayoutConstraint(item: button, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 1.0, constant: 0) + } + else + { + + let prevtButton = buttons[index-1] + leftConstraint = NSLayoutConstraint(item: button, attribute: .Left, relatedBy: .Equal, toItem: prevtButton, attribute: .Right, multiplier: 1.0, constant: 1) + + let firstButton = buttons[0] + let widthConstraint = NSLayoutConstraint(item: firstButton, attribute: .Width, relatedBy: .Equal, toItem: button, attribute: .Width, multiplier: 1.0, constant: 1) + + widthConstraint.priority = 800 + self.addConstraint(widthConstraint) + + } + + self.removeConstraints([topConstraint, bottomConstraint, leftConstraint]) + self.addConstraints([topConstraint, bottomConstraint, leftConstraint]) + } + } + else + { + let buttons = [btn4] + + for (index, button) in buttons.enumerate() { + + let topConstraint = NSLayoutConstraint(item: button, attribute: .Top, relatedBy: .Equal, toItem: self, attribute: .Top, multiplier: 1.0, constant: 0) + + let bottomConstraint = NSLayoutConstraint(item: button, attribute: .Bottom, relatedBy: .Equal, toItem: self, attribute: .Bottom, multiplier: 1.0, constant: 0) + + var rightConstraint : NSLayoutConstraint! + + if index == buttons.count - 1 + { + + rightConstraint = NSLayoutConstraint(item: button, attribute: .Right, relatedBy: .Equal, toItem: self, attribute: .Right, multiplier: 1.0, constant: 0) + self.addConstraint(rightConstraint) + } + + + var leftConstraint : NSLayoutConstraint! + + if index == 0 + { + + leftConstraint = NSLayoutConstraint(item: button, attribute: .Left, relatedBy: .Equal, toItem: self, attribute: .Left, multiplier: 0.5, constant: 0) + + } + +// else +// { +// +// let prevtButton = buttons[index-1] +// leftConstraint = NSLayoutConstraint(item: button, attribute: .Left, relatedBy: .Equal, toItem: prevtButton, attribute: .Right, multiplier: 1.0, constant: 6) +// +// let firstButton = buttons[0] +// var widthConstraint = NSLayoutConstraint(item: firstButton, attribute: .Width, relatedBy: .Equal, toItem: button, attribute: .Width, multiplier: 1.0, constant: 1) +// +// widthConstraint.priority = 800 +// self.addConstraint(widthConstraint) +// +// } + + // mainView.removeConstraints([topConstraint, bottomConstraint, rightConstraint, leftConstraint]) + // mainView.addConstraints([topConstraint, bottomConstraint, rightConstraint, leftConstraint]) + + self.removeConstraints([topConstraint, bottomConstraint, leftConstraint]) + self.addConstraints([topConstraint, bottomConstraint, leftConstraint]) + } + + } + + + + } + + override func touchesBegan(touches: Set, withEvent event: UIEvent?) + { + if self.frame.size.height == 30 + { + for obj in touches + { + let touch = obj + let position = touch.locationInView(self) + let view = findNearestView(position) + + let viewChangedOwnership = self.ownView(touch, viewToOwn: view) + if !viewChangedOwnership { + self.handleControl(view, controlEvent: .TouchDown) + + if touch.tapCount > 1 { + // two events, I think this is the correct behavior but I have not tested with an actual UIControl + self.handleControl(view, controlEvent: .TouchDownRepeat) + } + } + } + } + } + + override func touchesMoved(touches: Set, withEvent event: UIEvent?) + { + if self.frame.size.height == 30 + { + for obj in touches + { + let touch = obj + let position = touch.locationInView(self) + + let oldView = self.touchToView[touch] + let newView = findNearestView(position) + + if oldView != newView + { + self.handleControl(oldView, controlEvent: .TouchDragExit) + + let viewChangedOwnership = self.ownView(touch, viewToOwn: newView) + + if !viewChangedOwnership + { + self.handleControl(newView, controlEvent: .TouchDragEnter) + } + else + { + self.handleControl(newView, controlEvent: .TouchDragInside) + } + } + else + { + self.handleControl(oldView, controlEvent: .TouchDragInside) + } + + } + + } + + } + + override func touchesEnded(touches: Set, withEvent event: UIEvent?) + { + if self.frame.size.height == 30 + { + for obj in touches + { + let touch = obj + + let view = self.touchToView[touch] + + let touchPosition = touch.locationInView(self) + + if self.bounds.contains(touchPosition) + { + self.handleControl(view, controlEvent: .TouchUpInside) + } + else + { + self.handleControl(view, controlEvent: .TouchCancel) + } + + self.touchToView[touch] = nil + } + + } + + } + + override func touchesCancelled(touches: Set!, withEvent event: UIEvent!) + { + if self.frame.size.height == 30 + { + for obj in touches + { + let touch = obj + + let view = self.touchToView[touch] + + self.handleControl(view, controlEvent: .TouchCancel) + + self.touchToView[touch] = nil + } + } + + } + + // TODO: there's a bit of "stickiness" to Apple's implementation + func findNearestView(position: CGPoint) -> UIView? { + if !self.bounds.contains(position) { + return nil + } + + var closest: (UIView, CGFloat)? = nil + + for anyView in self.subviews { + let view = anyView + + if view.hidden { + continue + } + + view.alpha = 1 + + let distance = distanceBetween(view.frame, point: position) + + if closest != nil { + if distance < closest!.1 { + closest = (view, distance) + } + } + else { + closest = (view, distance) + } + } + + if closest != nil { + return closest!.0 + } + else { + return nil + } + } + + func distanceBetween(rect: CGRect, point: CGPoint) -> CGFloat { + if CGRectContainsPoint(rect, point) { + return 0 + } + + var closest = rect.origin + + if (rect.origin.x + rect.size.width < point.x) { + closest.x += rect.size.width + } + else if (point.x > rect.origin.x) { + closest.x = point.x + } + if (rect.origin.y + rect.size.height < point.y) { + closest.y += rect.size.height + } + else if (point.y > rect.origin.y) { + closest.y = point.y + } + + let a = pow(Double(closest.y - point.y), 2) + let b = pow(Double(closest.x - point.x), 2) + return CGFloat(sqrt(a + b)); + } + + func ownView(newTouch: UITouch, viewToOwn: UIView?) -> Bool { + var foundView = false + + if viewToOwn != nil { + for (touch, view) in self.touchToView { + if viewToOwn == view { + if touch == newTouch { + break + } + else { + self.touchToView[touch] = nil + foundView = true + } + break + } + } + } + + self.touchToView[newTouch] = viewToOwn + return foundView + } + + func handleControl(view: UIView?, controlEvent: UIControlEvents) { + if let control = view as? UIControl { + let targets = control.allTargets() + for target in targets { // TODO: Xcode crashes + let actions = control.actionsForTarget(target, forControlEvent: controlEvent) + if (actions != nil) { + for action in actions! { + let selector = Selector(action ) + + control.sendAction(selector, to: target, forEvent: nil) + } + } + } + } + + } + } diff --git a/Keyboard/DefaultKeyboard.swift b/Keyboard/DefaultKeyboard.swift index ce4467c3..ab612c43 100644 --- a/Keyboard/DefaultKeyboard.swift +++ b/Keyboard/DefaultKeyboard.swift @@ -3,18 +3,46 @@ // TransliteratingKeyboard // // Created by Alexei Baboulevitch on 7/10/14. -// Copyright (c) 2014 Alexei Baboulevitch ("Archagon"). All rights reserved. +// Copyright (c) 2014 Apple. All rights reserved. // -func defaultKeyboard() -> Keyboard { +func defaultKeyboard(keyboardType:UIKeyboardType) -> Keyboard +{ + + if keyboardType == UIKeyboardType.NumberPad + { + return defaultKeyboardNumber() + } + else if keyboardType == UIKeyboardType.DecimalPad + { + return defaultKeyboardDecimal() + } + else if keyboardType == UIKeyboardType.EmailAddress + { + return defaultKeyboardEmail() + } + else if keyboardType == UIKeyboardType.URL || keyboardType == UIKeyboardType.WebSearch + { + return defaultKeyboardURL() + } + else + { + return defaultKeyboardDefault() + } + +} + +func defaultKeyboardDefault() -> Keyboard { let defaultKeyboard = Keyboard() - + + var longPresses = generatedGetLongPresses(); + for key in ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"] { let keyModel = Key(.Character) keyModel.setLetter(key) defaultKeyboard.addKey(keyModel, row: 0, page: 0) } - + for key in ["A", "S", "D", "F", "G", "H", "J", "K", "L"] { let keyModel = Key(.Character) keyModel.setLetter(key) @@ -43,15 +71,24 @@ func defaultKeyboard() -> Keyboard { let settings = Key(.Settings) defaultKeyboard.addKey(settings, row: 3, page: 0) - + let space = Key(.Space) - space.uppercaseKeyCap = "space" + space.uppercaseKeyCap = "espacio" space.uppercaseOutput = " " space.lowercaseOutput = " " defaultKeyboard.addKey(space, row: 3, page: 0) - + +// var atModel = Key(.Character) +// atModel.setLetter("@") +// defaultKeyboard.addKey(atModel, row: 3, page: 0) + + +// var dotModel = Key(.Character) +// dotModel.setLetter(".") +// defaultKeyboard.addKey(dotModel, row: 3, page: 0) + let returnKey = Key(.Return) - returnKey.uppercaseKeyCap = "return" + returnKey.uppercaseKeyCap = "intro" returnKey.uppercaseOutput = "\n" returnKey.lowercaseOutput = "\n" defaultKeyboard.addKey(returnKey, row: 3, page: 0) @@ -127,4 +164,394 @@ func defaultKeyboard() -> Keyboard { defaultKeyboard.addKey(Key(returnKey), row: 3, page: 2) return defaultKeyboard + +} + + +func defaultKeyboardEmail() -> Keyboard { + let defaultKeyboard = Keyboard() + + var longPresses = generatedGetLongPresses(); + + for key in ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 0) + } + + for key in ["A", "S", "D", "F", "G", "H", "J", "K", "L"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 0) + } + + let keyModel = Key(.Shift) + defaultKeyboard.addKey(keyModel, row: 2, page: 0) + + for key in ["Z", "X", "C", "V", "B", "N", "M"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 0) + } + + let backspace = Key(.Backspace) + defaultKeyboard.addKey(backspace, row: 2, page: 0) + + let keyModeChangeNumbers = Key(.ModeChange) + keyModeChangeNumbers.uppercaseKeyCap = "123" + keyModeChangeNumbers.toMode = 1 + defaultKeyboard.addKey(keyModeChangeNumbers, row: 3, page: 0) + + let keyboardChange = Key(.KeyboardChange) + defaultKeyboard.addKey(keyboardChange, row: 3, page: 0) + + let settings = Key(.Settings) + defaultKeyboard.addKey(settings, row: 3, page: 0) + + let space = Key(.Space) + space.uppercaseKeyCap = "espacio" + space.uppercaseOutput = " " + space.lowercaseOutput = " " + defaultKeyboard.addKey(space, row: 3, page: 0) + + let atModel = Key(.Character) + atModel.setLetter("@") + defaultKeyboard.addKey(atModel, row: 3, page: 0) + + let dotModel = Key(.Character) + dotModel.setLetter(".") + defaultKeyboard.addKey(dotModel, row: 3, page: 0) + + let returnKey = Key(.Return) + returnKey.uppercaseKeyCap = "intro" + returnKey.uppercaseOutput = "\n" + returnKey.lowercaseOutput = "\n" + defaultKeyboard.addKey(returnKey, row: 3, page: 0) + + for key in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 1) + } + + for key in ["-", "/", ":", ";", "(", ")", "$", "&", "@", "\""] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 1) + } + + let keyModeChangeSpecialCharacters = Key(.ModeChange) + keyModeChangeSpecialCharacters.uppercaseKeyCap = "#+=" + keyModeChangeSpecialCharacters.toMode = 2 + defaultKeyboard.addKey(keyModeChangeSpecialCharacters, row: 2, page: 1) + + for key in [".", ",", "?", "!", "'"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 1) + } + + defaultKeyboard.addKey(Key(backspace), row: 2, page: 1) + + let keyModeChangeLetters = Key(.ModeChange) + keyModeChangeLetters.uppercaseKeyCap = "ABC" + keyModeChangeLetters.toMode = 0 + defaultKeyboard.addKey(keyModeChangeLetters, row: 3, page: 1) + + defaultKeyboard.addKey(Key(keyboardChange), row: 3, page: 1) + + defaultKeyboard.addKey(Key(settings), row: 3, page: 1) + + defaultKeyboard.addKey(Key(space), row: 3, page: 1) + + defaultKeyboard.addKey(Key(returnKey), row: 3, page: 1) + + for key in ["[", "]", "{", "}", "#", "%", "^", "*", "+", "="] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 2) + } + + for key in ["_", "\\", "|", "~", "<", ">", "€", "£", "¥", "•"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 2) + } + + defaultKeyboard.addKey(Key(keyModeChangeNumbers), row: 2, page: 2) + + for key in [".", ",", "?", "!", "'"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 2) + } + + defaultKeyboard.addKey(Key(backspace), row: 2, page: 2) + + defaultKeyboard.addKey(Key(keyModeChangeLetters), row: 3, page: 2) + + defaultKeyboard.addKey(Key(keyboardChange), row: 3, page: 2) + + defaultKeyboard.addKey(Key(settings), row: 3, page: 2) + + defaultKeyboard.addKey(Key(space), row: 3, page: 2) + + defaultKeyboard.addKey(Key(returnKey), row: 3, page: 2) + + return defaultKeyboard + +} + + +func defaultKeyboardURL() -> Keyboard { + let defaultKeyboard = Keyboard() + + var longPresses = generatedGetLongPresses(); + + for key in ["Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 0) + } + + for key in ["A", "S", "D", "F", "G", "H", "J", "K", "L"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 0) + } + + let keyModel = Key(.Shift) + defaultKeyboard.addKey(keyModel, row: 2, page: 0) + + for key in ["Z", "X", "C", "V", "B", "N", "M"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 0) + } + + let backspace = Key(.Backspace) + defaultKeyboard.addKey(backspace, row: 2, page: 0) + + let keyModeChangeNumbers = Key(.ModeChange) + keyModeChangeNumbers.uppercaseKeyCap = "123" + keyModeChangeNumbers.toMode = 1 + defaultKeyboard.addKey(keyModeChangeNumbers, row: 3, page: 0) + + let keyboardChange = Key(.KeyboardChange) + defaultKeyboard.addKey(keyboardChange, row: 3, page: 0) + + let settings = Key(.Settings) + defaultKeyboard.addKey(settings, row: 3, page: 0) + + let space = Key(.Space) + space.uppercaseKeyCap = "espacio" + space.uppercaseOutput = " " + space.lowercaseOutput = " " + defaultKeyboard.addKey(space, row: 3, page: 0) + + let dotModel = Key(.Character) + dotModel.setLetter(".") + defaultKeyboard.addKey(dotModel, row: 3, page: 0) + + let returnKey = Key(.Return) + returnKey.uppercaseKeyCap = "intro" + returnKey.uppercaseOutput = "\n" + returnKey.lowercaseOutput = "\n" + defaultKeyboard.addKey(returnKey, row: 3, page: 0) + + for key in ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 1) + } + + for key in ["-", "/", ":", ";", "(", ")", "$", "&", "@", "\""] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 1) + } + + let keyModeChangeSpecialCharacters = Key(.ModeChange) + keyModeChangeSpecialCharacters.uppercaseKeyCap = "#+=" + keyModeChangeSpecialCharacters.toMode = 2 + defaultKeyboard.addKey(keyModeChangeSpecialCharacters, row: 2, page: 1) + + for key in [".", ",", "?", "!", "'"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 1) + } + + defaultKeyboard.addKey(Key(backspace), row: 2, page: 1) + + let keyModeChangeLetters = Key(.ModeChange) + keyModeChangeLetters.uppercaseKeyCap = "ABC" + keyModeChangeLetters.toMode = 0 + defaultKeyboard.addKey(keyModeChangeLetters, row: 3, page: 1) + + defaultKeyboard.addKey(Key(keyboardChange), row: 3, page: 1) + + defaultKeyboard.addKey(Key(settings), row: 3, page: 1) + + defaultKeyboard.addKey(Key(space), row: 3, page: 1) + + defaultKeyboard.addKey(Key(returnKey), row: 3, page: 1) + + for key in ["[", "]", "{", "}", "#", "%", "^", "*", "+", "="] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 2) + } + + for key in ["_", "\\", "|", "~", "<", ">", "€", "£", "¥", "•"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 2) + } + + defaultKeyboard.addKey(Key(keyModeChangeNumbers), row: 2, page: 2) + + for key in [".", ",", "?", "!", "'"] { + let keyModel = Key(.SpecialCharacter) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 2) + } + + defaultKeyboard.addKey(Key(backspace), row: 2, page: 2) + + defaultKeyboard.addKey(Key(keyModeChangeLetters), row: 3, page: 2) + + defaultKeyboard.addKey(Key(keyboardChange), row: 3, page: 2) + + defaultKeyboard.addKey(Key(settings), row: 3, page: 2) + + defaultKeyboard.addKey(Key(space), row: 3, page: 2) + + defaultKeyboard.addKey(Key(returnKey), row: 3, page: 2) + + return defaultKeyboard + +} + +func defaultKeyboardDecimal() -> Keyboard { + let defaultKeyboard = Keyboard() + + for key in ["1", "2", "3","."] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 0) + } + + for key in ["4", "5", "6",","] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 0) + } + + for key in ["7", "8","9","-"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 0) + } + + let keyboardChange = Key(.KeyboardChange) + // defaultKeyboard.addKey(keyboardChange, row: 3, page: 0) + + for key in ["00","0"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 3, page: 0) + + } + + let backspace = Key(.Backspace) + + defaultKeyboard.addKey(keyboardChange, row: 3, page: 0) + + defaultKeyboard.addKey(backspace, row: 3, page: 0) + + + + return defaultKeyboard +} + + +func defaultKeyboardNumber() -> Keyboard { + let defaultKeyboard = Keyboard() + + for key in ["1", "2", "3","."] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 0, page: 0) + } + + for key in ["4", "5", "6",","] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 1, page: 0) + } + + for key in ["7", "8","9","-"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 2, page: 0) + } + + let keyboardChange = Key(.KeyboardChange) +// defaultKeyboard.addKey(keyboardChange, row: 3, page: 0) + + for key in ["00","0"] { + let keyModel = Key(.Character) + keyModel.setLetter(key) + defaultKeyboard.addKey(keyModel, row: 3, page: 0) + + } + + let backspace = Key(.Backspace) + + defaultKeyboard.addKey(keyboardChange, row: 3, page: 0) + + defaultKeyboard.addKey(backspace, row: 3, page: 0) + + + + return defaultKeyboard +} + + +func generatedGetLongPresses() -> [String: [String]] { + var lps = [String: [String]]() + lps["k"] = ["ǩ"] + lps["t"] = ["ŧ", "þ"] + lps["d"] = ["đ", "ð"] + lps["D"] = ["Đ", "Ð"] + lps["Z"] = ["Ž", "Ʒ", "Ǯ"] + lps["u"] = ["ü", "ú", "ù", "û", "ũ", "ū", "ŭ"] + lps["n"] = ["ŋ"] + lps["c"] = ["č", "ç"] + lps["e"] = ["ë", "é", "è", "ê", "ẽ", "ė", "ē", "ĕ", "ę"] + lps["Æ"] = ["Ä"] + lps["Ø"] = ["Ö"] + lps["æ"] = ["ä"] + lps["A"] = ["Æ", "Ä", "Å", "Á", "À", "Â", "Ã", "Ȧ", "Ā"] + lps["s"] = ["š"] + lps["ø"] = ["ö"] + lps["S"] = ["Š"] + lps["K"] = ["Ǩ"] + lps["G"] = ["Ĝ", "Ḡ", "Ǧ", "Ǥ"] + lps["O"] = ["Œ", "Ö", "Ó", "Ò", "Ô", "Õ", "Ō", "Ŏ"] + lps["C"] = ["Č", "Ç"] + lps["a"] = ["æ", "ä", "å", "á", "à", "â", "ã", "ȧ", "ā"] + lps["E"] = ["Ë", "É", "È", "Ê", "Ẽ", "Ė", "Ē", "Ĕ", "Ę"] + lps["N"] = ["Ŋ"] + lps["g"] = ["ĝ", "ḡ", "ǧ", "ǥ"] + lps["U"] = ["Ü", "Ú", "Ù", "Û", "Ũ", "Ū", "Ŭ"] + lps["i"] = ["ï", "í", "ì", "î", "ĩ", "ī", "ĭ"] + lps["z"] = ["ž", "ʒ", "ǯ"] + lps["o"] = ["œ", "ö", "ó", "ò", "ô", "õ", "ō", "ŏ"] + lps["I"] = ["Ï", "Í", "Ì", "Î", "Ĩ", "Ī", "Ĭ"] + lps["Y"] = ["Ý", "Ỳ", "Ŷ", "Ẏ", "Ȳ"] + lps["y"] = ["ý", "ỳ", "ŷ", "ẏ", "ȳ"] + lps["T"] = ["Ŧ", "Þ"] + return lps } diff --git a/Keyboard/DefaultSettings.swift b/Keyboard/DefaultSettings.swift index 45e38573..bd3a5a72 100644 --- a/Keyboard/DefaultSettings.swift +++ b/Keyboard/DefaultSettings.swift @@ -62,10 +62,11 @@ class DefaultSettings: ExtraView, UITableViewDataSource, UITableViewDelegate { self.loadNib() } + required init?(coder aDecoder: NSCoder) { - fatalError("loading from nib not supported") + fatalError("init(coder:) has not been implemented") } - + func loadNib() { let assets = NSBundle(forClass: self.dynamicType).loadNibNamed("DefaultSettings", owner: self, options: nil) @@ -126,7 +127,7 @@ class DefaultSettings: ExtraView, UITableViewDataSource, UITableViewDelegate { let key = self.settingsList[indexPath.section].1[indexPath.row] if cell.sw.allTargets().count == 0 { - cell.sw.addTarget(self, action: Selector("toggleSetting:"), forControlEvents: UIControlEvents.ValueChanged) + cell.sw.addTarget(self, action: #selector(DefaultSettings.toggleSetting(_:)), forControlEvents: UIControlEvents.ValueChanged) } cell.sw.on = NSUserDefaults.standardUserDefaults().boolForKey(key) @@ -231,10 +232,11 @@ class DefaultSettingsTableViewCell: UITableViewCell { self.addConstraints() } + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + func addConstraints() { let margin: CGFloat = 8 let sideMargin = margin * 2 diff --git a/Keyboard/ExtraView.swift b/Keyboard/ExtraView.swift index 794f9e45..e82e90e1 100644 --- a/Keyboard/ExtraView.swift +++ b/Keyboard/ExtraView.swift @@ -13,7 +13,12 @@ class ExtraView: UIView { var globalColors: GlobalColors.Type? var darkMode: Bool var solidColorMode: Bool - + + var btn1 : UIButton = UIButton() + var btn2 : UIButton = UIButton() + var btn3 : UIButton = UIButton() + var btn4 : UIButton = UIButton() + required init(globalColors: GlobalColors.Type?, darkMode: Bool, solidColorMode: Bool) { self.globalColors = globalColors self.darkMode = darkMode @@ -23,6 +28,7 @@ class ExtraView: UIView { } required init?(coder aDecoder: NSCoder) { + self.globalColors = nil self.darkMode = false self.solidColorMode = false diff --git a/Keyboard/ForwardingView.swift b/Keyboard/ForwardingView.swift index 6779fb8f..9be3d6e4 100644 --- a/Keyboard/ForwardingView.swift +++ b/Keyboard/ForwardingView.swift @@ -3,15 +3,23 @@ // TransliteratingKeyboard // // Created by Alexei Baboulevitch on 7/19/14. -// Copyright (c) 2014 Alexei Baboulevitch ("Archagon"). All rights reserved. +// Copyright (c) 2014 Apple. All rights reserved. // import UIKit -class ForwardingView: UIView { +class ForwardingView: UIView,UIGestureRecognizerDelegate { var touchToView: [UITouch:UIView] - + + var gesture = UILongPressGestureRecognizer() + + var isLongPressEnable = false + var isLongPressKeyPress = false + + var currentMode: Int = 0 + var keyboard_type: UIKeyboardType? + override init(frame: CGRect) { self.touchToView = [:] @@ -21,6 +29,14 @@ class ForwardingView: UIView { self.multipleTouchEnabled = true self.userInteractionEnabled = true self.opaque = false + + gesture = UILongPressGestureRecognizer(target: self, action: #selector(ForwardingView.handleLongGesture(_:))) + + gesture.minimumPressDuration = 0.5 + gesture.delegate = self + gesture.cancelsTouchesInView = false + self.addGestureRecognizer(gesture) + } required init?(coder: NSCoder) { @@ -48,16 +64,129 @@ class ForwardingView: UIView { for target in targets { if let actions = control.actionsForTarget(target, forControlEvent: controlEvent) { for action in actions { - let selectorString = action - let selector = Selector(selectorString) - control.sendAction(selector, to: target, forEvent: nil) + let selector = Selector(action) + control.sendAction(selector, to: target, forEvent: nil) } - } } } } - + + @IBAction func handleLongGesture(longPress: UIGestureRecognizer) + { + if (longPress.state == UIGestureRecognizerState.Ended) + { + //println("Ended") + + let position = longPress.locationInView(self) + let view = findNearestView(position) + + if view is KeyboardKey + { + NSNotificationCenter.defaultCenter().postNotificationName("hideExpandViewNotification", object: nil) + } + + isLongPressEnable = false + + isLongPressKeyPress = true + + if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad + { + let keyboardKey = view as! KeyboardKey + keyboardKey.highlighted = false + } + + + } + else if (longPress.state == UIGestureRecognizerState.Began) + { + if (longPress.state == UIGestureRecognizerState.Began) + { + //println("Began") + + isLongPressEnable = true + + let position = longPress.locationInView(self) + let view = findNearestView(position) + + let viewChangedOwnership = false + + if !viewChangedOwnership { + + if view is KeyboardKey + { + let v = view as! KeyboardKey + if self.isLongPressEnableKey(v.text) + { + view!.tag = 888 + + self.handleControl(view, controlEvent: .TouchDownRepeat) + } + + } + } + } + } + } + + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool + { + if gestureRecognizer is UILongPressGestureRecognizer + { + if (gestureRecognizer.state == UIGestureRecognizerState.Possible) + { + let position = touch.locationInView(self) + let view = findNearestView(position) + + let viewChangedOwnership = false + + if !viewChangedOwnership { + + if view is KeyboardKey + { + let v = view as! KeyboardKey + if self.isLongPressEnableKey(v.text) + { + return true + } + } + } + return false + } + else if (gestureRecognizer.state == UIGestureRecognizerState.Ended) + { + let position = gestureRecognizer.locationInView(self) + let view = findNearestView(position) + + let viewChangedOwnership = false + + if !viewChangedOwnership { + + if view is KeyboardKey + { + let v = view as! KeyboardKey + if self.isLongPressEnableKey(v.text) + { + return true + } + } + } + return false + } + } + else + { + return true + } + return false + } + + func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool + { + return true + } + // TODO: there's a bit of "stickiness" to Apple's implementation func findNearestView(position: CGPoint) -> UIView? { if !self.bounds.contains(position) { @@ -66,24 +195,23 @@ class ForwardingView: UIView { var closest: (UIView, CGFloat)? = nil - for anyView in self.subviews { - let view = anyView - if view.hidden { - continue - } - - view.alpha = 1 - - let distance = distanceBetween(view.frame, point: position) - - if closest != nil { - if distance < closest!.1 { + for view in self.subviews { + if view.hidden { + continue + } + + view.alpha = 1 + + let distance = distanceBetween(view.frame, point: position) + + if closest != nil { + if distance < closest!.1 { + closest = (view, distance) + } + } + else { closest = (view, distance) } - } - else { - closest = (view, distance) - } } if closest != nil { @@ -127,7 +255,15 @@ class ForwardingView: UIView { } self.touchToView.removeAll(keepCapacity: true) } - + + func resetPopUpViews() { + for view in self.touchToView.values { + + let v = view as! KeyboardKey + v.hidePopup() + } + } + func ownView(newTouch: UITouch, viewToOwn: UIView?) -> Bool { var foundView = false @@ -150,75 +286,236 @@ class ForwardingView: UIView { return foundView } - override func touchesBegan(touches: Set, withEvent event: UIEvent?) { - for touch in touches { - let position = touch.locationInView(self) - let view = findNearestView(position) - - let viewChangedOwnership = self.ownView(touch, viewToOwn: view) - - if !viewChangedOwnership { - self.handleControl(view, controlEvent: .TouchDown) - - if touch.tapCount > 1 { - // two events, I think this is the correct behavior but I have not tested with an actual UIControl - self.handleControl(view, controlEvent: .TouchDownRepeat) - } - } - } - } - - override func touchesMoved(touches: Set, withEvent event: UIEvent?) { - for touch in touches { - let position = touch.locationInView(self) - - let oldView = self.touchToView[touch] - let newView = findNearestView(position) - - if oldView != newView { - self.handleControl(oldView, controlEvent: .TouchDragExit) - - let viewChangedOwnership = self.ownView(touch, viewToOwn: newView) - - if !viewChangedOwnership { - self.handleControl(newView, controlEvent: .TouchDragEnter) - } - else { - self.handleControl(newView, controlEvent: .TouchDragInside) - } - } - else { - self.handleControl(oldView, controlEvent: .TouchDragInside) - } - } - } - - override func touchesEnded(touches: Set, withEvent event: UIEvent?) { - for touch in touches { - let view = self.touchToView[touch] - - let touchPosition = touch.locationInView(self) - - if self.bounds.contains(touchPosition) { - self.handleControl(view, controlEvent: .TouchUpInside) - } - else { - self.handleControl(view, controlEvent: .TouchCancel) - } - - self.touchToView[touch] = nil - } - } + override func touchesBegan(touches: Set, withEvent event: UIEvent?) { + // println("touchesBegan") + for obj in touches { + let touch = obj + let position = touch.locationInView(self) + let view = findNearestView(position) + + let viewChangedOwnership = self.ownView(touch, viewToOwn: view) + + if(isLongPressEnable == true) + { + if view != nil + { + if !viewChangedOwnership + { + self.handleControl(view, controlEvent: .TouchDown) + //self.touchToView[touch] = nil + } + } + + NSNotificationCenter.defaultCenter().postNotificationName("hideExpandViewNotification", object: nil) + isLongPressEnable = false + + if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad + { + let keyboardKey = view as! KeyboardKey + keyboardKey.highlighted = false + } + + } + else + { + if !viewChangedOwnership { + self.handleControl(view, controlEvent: .TouchDown) + + if touch.tapCount > 1 { + // two events, I think this is the correct behavior but I have not tested with an actual UIControl + self.handleControl(view, controlEvent: .TouchDownRepeat) + } + } + } + + } + } + + override func touchesMoved(touches: Set, withEvent event: UIEvent?) { + //println("touchesMoved") + for obj in touches + { + let touch = obj + let position = touch.locationInView(self) + + if(isLongPressEnable) + { + let expandedButtonView : CYRKeyboardButtonView! = self.getCYRView() + + if expandedButtonView != nil + { + expandedButtonView.updateSelectedInputIndexForPoint(position) + } + } + else + { + let oldView = self.touchToView[touch] + let newView = findNearestView(position) + + if oldView != newView + { + self.handleControl(oldView, controlEvent: .TouchDragExit) + + let viewChangedOwnership = self.ownView(touch, viewToOwn: newView) + + if !viewChangedOwnership + { + self.handleControl(newView, controlEvent: .TouchDragEnter) + } + else + { + self.handleControl(newView, controlEvent: .TouchDragInside) + } + } + else + { + self.handleControl(oldView, controlEvent: .TouchDragInside) + } + } + } + } + + override func touchesEnded(touches: Set, withEvent event: UIEvent?) { + for obj in touches { + + let touch = obj + + let view = self.touchToView[touch] + + let touchPosition = touch.locationInView(self) + + if(isLongPressKeyPress == true) + { + let expandedButtonView : CYRKeyboardButtonView! = self.getCYRView() + if (expandedButtonView.selectedInputIndex != NSNotFound) + { + let inputOption = self.getCYRButton().inputOptions[expandedButtonView.selectedInputIndex] as! String + + self.resetPopUpViews() + + NSNotificationCenter.defaultCenter().postNotificationName("hideExpandViewNotification", object: nil, userInfo: ["text":inputOption]) + + } + + isLongPressKeyPress = false + + if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad + { + let keyboardKey = view as! KeyboardKey + keyboardKey.highlighted = false + } + + } + else + { + if self.bounds.contains(touchPosition) + { + self.handleControl(view, controlEvent: .TouchUpInside) + } + else + { + self.handleControl(view, controlEvent: .TouchCancel) + } + + //self.touchToView[touch] = nil + } + + self.touchToView[touch] = nil + } + } override func touchesCancelled(touches: Set?, withEvent event: UIEvent?) { - if let touches = touches { - for touch in touches { - let view = self.touchToView[touch] + for obj in touches! { + let view = self.touchToView[obj] self.handleControl(view, controlEvent: .TouchCancel) - self.touchToView[touch] = nil - } + self.touchToView[obj] = nil } } + + func isLongPressEnableKey(text:NSString) -> Bool + { + let alphabet_lengh = text.length + + if(alphabet_lengh > 1) + { + return false + } + + let alphaBets = NSCharacterSet(charactersInString: "AEUIOSDCNaeuiosdcn.") + + if text.rangeOfCharacterFromSet(alphaBets).location != NSNotFound + { + if self.currentMode == 0 + { + if(keyboard_type == UIKeyboardType.DecimalPad || keyboard_type == UIKeyboardType.NumberPad) + { + return false + } + + return true + } + + } + + return false + } + + func isSubViewContainsCYRView() -> Bool + { + for anyView in self.superview!.subviews + { + if anyView is CYRKeyboardButtonView + { + return true + } + } + return false + } + + func getCYRView() -> CYRKeyboardButtonView! + { + if isSubViewContainsCYRView() + { + for anyView in self.superview!.subviews + { + if anyView is CYRKeyboardButtonView + { + return anyView as! CYRKeyboardButtonView + } + } + } + + return nil + } + + func isSubViewContainsCYRButton() -> Bool + { + for anyView in self.superview!.subviews + { + if anyView is CYRKeyboardButton + { + return true + } + } + return false + } + + func getCYRButton() -> CYRKeyboardButton! + { + if isSubViewContainsCYRButton() + { + for anyView in self.superview!.subviews + { + if anyView is CYRKeyboardButton + { + return anyView as! CYRKeyboardButton + } + } + } + + return nil + } + } diff --git a/Keyboard/Keyboard-Bridging-Header.h b/Keyboard/Keyboard-Bridging-Header.h new file mode 100644 index 00000000..a2ca1b26 --- /dev/null +++ b/Keyboard/Keyboard-Bridging-Header.h @@ -0,0 +1,4 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// +#import "CYRKeyboardButton.h" diff --git a/Keyboard/KeyboardConnector.swift b/Keyboard/KeyboardConnector.swift index 70055895..141d71b4 100644 --- a/Keyboard/KeyboardConnector.swift +++ b/Keyboard/KeyboardConnector.swift @@ -45,7 +45,7 @@ class KeyboardConnector: KeyboardKeyBackground { } required init?(coder: NSCoder) { - fatalError("NSCoding not supported") + fatalError("init(coder:) has not been implemented") } override func didMoveToSuperview() { diff --git a/Keyboard/KeyboardInputTraits.swift b/Keyboard/KeyboardInputTraits.swift index ee64dd4e..dea7bff3 100644 --- a/Keyboard/KeyboardInputTraits.swift +++ b/Keyboard/KeyboardInputTraits.swift @@ -24,7 +24,7 @@ extension KeyboardViewController { func addInputTraitsObservers() { // note that KVO doesn't work on textDocumentProxy, so we have to poll traitPollingTimer?.invalidate() - traitPollingTimer = UIScreen.mainScreen().displayLinkWithTarget(self, selector: Selector("pollTraits")) + traitPollingTimer = UIScreen.mainScreen().displayLinkWithTarget(self, selector: #selector(KeyboardViewController.pollTraits)) traitPollingTimer?.addToRunLoop(NSRunLoop.currentRunLoop(), forMode: NSDefaultRunLoopMode) } diff --git a/Keyboard/KeyboardKey.swift b/Keyboard/KeyboardKey.swift index d8b92eda..ce62b24e 100644 --- a/Keyboard/KeyboardKey.swift +++ b/Keyboard/KeyboardKey.swift @@ -156,7 +156,7 @@ class KeyboardKey: UIControl { self.addSubview(self.background) self.background.addSubview(self.label) - let setupViews: Void = { + let _: Void = { self.displayView.opaque = false self.underView?.opaque = false self.borderView?.opaque = false @@ -179,7 +179,7 @@ class KeyboardKey: UIControl { } required init?(coder: NSCoder) { - fatalError("NSCoding not supported") + fatalError("NSCoding not supported") } override func setNeedsLayout() { @@ -450,7 +450,7 @@ class KeyboardKey: UIControl { } } - func hidePopup() { + @objc func hidePopup() { if self.popup != nil { self.delegate?.willHidePopup(self) @@ -552,6 +552,7 @@ class ShapeView: UIView { } required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") } diff --git a/Keyboard/KeyboardKeyBackground.swift b/Keyboard/KeyboardKeyBackground.swift index ba7b3760..8eb3f1eb 100644 --- a/Keyboard/KeyboardKeyBackground.swift +++ b/Keyboard/KeyboardKeyBackground.swift @@ -70,8 +70,9 @@ class KeyboardKeyBackground: UIView, Connectable { self.userInteractionEnabled = false } - required init?(coder: NSCoder) { - fatalError("NSCoding not supported") + + required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") } var oldBounds: CGRect? diff --git a/Keyboard/KeyboardLayout.swift b/Keyboard/KeyboardLayout.swift index 5e5fb774..f55d0aac 100644 --- a/Keyboard/KeyboardLayout.swift +++ b/Keyboard/KeyboardLayout.swift @@ -23,9 +23,9 @@ class LayoutConstants: NSObject { class var topEdgeLandscape: CGFloat { get { return 6 }} // keyboard area shrinks in size in landscape on 6 and 6+ - class var keyboardShrunkSizeArray: [CGFloat] { get { return [522, 524] }} + class var keyboardShrunkSizeArray: [CGFloat] { get { return [660, 524] }} class var keyboardShrunkSizeWidthThreshholds: [CGFloat] { get { return [700] }} - class var keyboardShrunkSizeBaseWidthThreshhold: CGFloat { get { return 600 }} + class var keyboardShrunkSizeBaseWidthThreshhold: CGFloat { get { return 740 }} // row gaps are weird on 6 in portrait class var rowGapPortraitArray: [CGFloat] { get { return [15, 11, 10] }} @@ -39,7 +39,7 @@ class LayoutConstants: NSObject { class var keyGapPortraitSmall: CGFloat { get { return 5 }} class var keyGapPortraitNormalThreshhold: CGFloat { get { return 350 }} class var keyGapPortraitUncompressThreshhold: CGFloat { get { return 350 }} - class var keyGapLandscapeNormal: CGFloat { get { return 6 }} + class var keyGapLandscapeNormal: CGFloat { get { return 10 }} class var keyGapLandscapeSmall: CGFloat { get { return 5 }} // TODO: 5.5 row gap on 5L // TODO: wider row gap on 6L @@ -267,7 +267,8 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { var solidColorMode: Bool var initialized: Bool - required init(model: Keyboard, superview: UIView, layoutConstants: LayoutConstants.Type, globalColors: GlobalColors.Type, darkMode: Bool, solidColorMode: Bool) { + required init(model: Keyboard, superview: UIView, layoutConstants: LayoutConstants.Type, globalColors: GlobalColors.Type, darkMode: Bool, solidColorMode: Bool) + { self.layoutConstants = layoutConstants self.globalColors = globalColors @@ -280,7 +281,8 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { } // TODO: remove this method - func initialize() { + func initialize() + { assert(!self.initialized, "already initialized") self.initialized = true } @@ -320,6 +322,8 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { for (_, key) in row.enumerate() { if let keyView = self.modelToView[key] { keyView.hidePopup() + + //keyView.hideLongPress() keyView.highlighted = false keyView.hidden = (p != pageNum) } @@ -362,7 +366,7 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { } } - foundCachedKeys.map { + let _ = foundCachedKeys.map { keyMap.removeValueForKey($0) } @@ -530,25 +534,37 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { case Key.KeyType.Space: key.color = self.globalColors.regularKey(darkMode, solidColorMode: solidColorMode) - key.downColor = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + //key.downColor = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + + key.downColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + key.textColor = (darkMode ? self.globalColors.darkModeTextColor : self.globalColors.lightModeTextColor) key.downTextColor = nil case Key.KeyType.Shift: - key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + // key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + + key.color = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + key.downColor = (darkMode ? self.globalColors.darkModeShiftKeyDown : self.globalColors.lightModeRegularKey) key.textColor = self.globalColors.darkModeTextColor key.downTextColor = self.globalColors.lightModeTextColor case Key.KeyType.Backspace: - key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + //key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + + key.color = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + // TODO: actually a bit different key.downColor = self.globalColors.regularKey(darkMode, solidColorMode: solidColorMode) key.textColor = self.globalColors.darkModeTextColor key.downTextColor = (darkMode ? nil : self.globalColors.lightModeTextColor) case Key.KeyType.ModeChange: - key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + //key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + + key.color = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + key.downColor = nil key.textColor = (darkMode ? self.globalColors.darkModeTextColor : self.globalColors.lightModeTextColor) key.downTextColor = nil @@ -556,7 +572,10 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { Key.KeyType.Return, Key.KeyType.KeyboardChange, Key.KeyType.Settings: - key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + //key.color = self.globalColors.specialKey(darkMode, solidColorMode: solidColorMode) + + key.color = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + // TODO: actually a bit different key.downColor = self.globalColors.regularKey(darkMode, solidColorMode: solidColorMode) key.textColor = (darkMode ? self.globalColors.darkModeTextColor : self.globalColors.lightModeTextColor) @@ -779,7 +798,7 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { let mostKeysInRow: Int = { var currentMax: Int = 0 - for (i, row) in page.rows.enumerate() { + for (_, row) in page.rows.enumerate() { currentMax = max(currentMax, row.count) } return currentMax @@ -907,7 +926,7 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { let specialCharacterGap = sideSpace - specialCharacterWidth var currentOrigin = frame.origin.x - for (k, key) in row.enumerate() { + for (k, _) in row.enumerate() { if k == 0 { frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, specialCharacterWidth, frame.height)) currentOrigin += (specialCharacterWidth + specialCharacterGap) @@ -937,7 +956,7 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { var keysBeforeSpace = 0 var keysAfterSpace = 0 var reachedSpace = false - for (k, key) in row.enumerate() { + for (_, key) in row.enumerate() { if key.type == Key.KeyType.Space { reachedSpace = true } @@ -951,10 +970,14 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { } } - assert(keysBeforeSpace <= 3, "invalid number of keys before space (only max 3 currently supported)") - assert(keysAfterSpace == 1, "invalid number of keys after space (only default 1 currently supported)") - +// assert(keysBeforeSpace <= 3, "invalid number of keys before space (only max 3 currently supported)") +// assert(keysAfterSpace == 1, "invalid number of keys after space (only default 1 currently supported)") + let hasButtonInMicButtonPosition = (keysBeforeSpace == 3) + + let hasButtonInDotButtonPosition = (keysAfterSpace == 2) + + let hasButtonInAtButtonPosition = (keysAfterSpace == 3) var leftSideAreaWidth = frame.width * leftSideRatio let rightSideAreaWidth = frame.width * rightSideRatio @@ -964,20 +987,36 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { rightButtonWidth = rounded(rightButtonWidth) let micButtonWidth = (isLandscape ? leftButtonWidth : leftButtonWidth * micButtonRatio) - + + let dotButtonWidth = (isLandscape ? rightButtonWidth : leftButtonWidth * micButtonRatio) + + let atButtonWidth = (isLandscape ? rightButtonWidth : leftButtonWidth * micButtonRatio) + // special case for mic button if hasButtonInMicButtonPosition { leftSideAreaWidth = leftSideAreaWidth + gapWidth + micButtonWidth } var spaceWidth = frame.width - leftSideAreaWidth - rightSideAreaWidth - gapWidth * CGFloat(2) + spaceWidth = rounded(spaceWidth) - + + if hasButtonInDotButtonPosition + { + spaceWidth -= 20 + } + + if hasButtonInAtButtonPosition + { + spaceWidth -= 40 + } + var currentOrigin = frame.origin.x var beforeSpace: Bool = true for (k, key) in row.enumerate() { if key.type == Key.KeyType.Space { - frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, spaceWidth, frame.height)) + + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, spaceWidth , frame.height)) currentOrigin += (spaceWidth + gapWidth) beforeSpace = false } @@ -987,13 +1026,240 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { currentOrigin += (micButtonWidth + gapWidth) } else { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, leftButtonWidth, frame.height)) currentOrigin += (leftButtonWidth + gapWidth) + } } - else { - frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth, frame.height)) - currentOrigin += (rightButtonWidth + gapWidth) + else + { + if hasButtonInDotButtonPosition && k == 4 + { + frames.append(CGRectMake(rounded(currentOrigin), + frame.origin.y, + dotButtonWidth, + frame.height)) + + currentOrigin += (dotButtonWidth + gapWidth) + } + else if hasButtonInDotButtonPosition && k == 5 + { + + if(isLandscape == true) + { + if(UIScreen.mainScreen().bounds.width == 736 && rightButtonWidth >= 67) // 6plus original + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.29, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad + { + if(rightButtonWidth == 70) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.3, frame.height)) + + } + else // rightButtonWidth = 94 (ipad landscape) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.22, frame.height)) + } + + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 736 && rightButtonWidth >= 41) //6plus without splash + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.5, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 667 && rightButtonWidth == 41) //6 without splash + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.47, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 667 && rightButtonWidth >= 59) //6 original + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.32, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 480 && rightButtonWidth >= 41) //6 original + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.48, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.4, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + } + else + { + if(UIScreen.mainScreen().bounds.width == 414 && rightButtonWidth >= 45) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.65, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 414 && rightButtonWidth >= 28) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.8, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 375 && rightButtonWidth >= 41) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.7, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 375 && rightButtonWidth >= 25) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.8, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.82, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + + } + + } + else if hasButtonInAtButtonPosition + { + if k == 4 + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, atButtonWidth, frame.height)) + currentOrigin += (atButtonWidth + gapWidth) + } + else if k == 5 + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, dotButtonWidth, frame.height)) + currentOrigin += (dotButtonWidth + gapWidth) + } + else if k == 6 + { + // intro button constarints for iPhone 6 and 6plus + + if(isLandscape) + { + if(UIScreen.mainScreen().bounds.width == 736 && rightButtonWidth == 43) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.9, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad + { + if(rightButtonWidth == 45) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.88, frame.height)) + } + else // ipad landscape + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 1.68, frame.height)) + } + + } + else if(UIScreen.mainScreen().bounds.width == 736 && rightButtonWidth >= 21) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.6, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 667 && rightButtonWidth == 37) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.1, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 667 && rightButtonWidth >= 24) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.65, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 480 && rightButtonWidth >= 24) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.67, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + + else + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth*2.3, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + + } + else + { + if(UIScreen.mainScreen().bounds.width == 414 && rightButtonWidth == 21) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.4, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 414 && rightButtonWidth >= 28) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.0, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 375 && rightButtonWidth == 21) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.4, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if(UIScreen.mainScreen().bounds.width == 375 && rightButtonWidth >= 25) + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth * 2.1, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth*2.4, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + + } + + + } + else + { + let widthTotal = UIScreen.mainScreen().bounds.width + + let widthOfSpace = widthTotal - rounded(currentOrigin) - (gapWidth/2) + + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, widthOfSpace, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + + } + + } + else + { + if hasButtonInDotButtonPosition + { + let widthTotal = UIScreen.mainScreen().bounds.width + + let widthOfSpace = widthTotal - rounded(currentOrigin) - (gapWidth/2) + + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, widthOfSpace, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else if hasButtonInAtButtonPosition + { + let widthTotal = UIScreen.mainScreen().bounds.width + + let widthOfSpace = widthTotal - rounded(currentOrigin) - (gapWidth/2) + + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, widthOfSpace, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + else + { + frames.append(CGRectMake(rounded(currentOrigin), frame.origin.y, rightButtonWidth, frame.height)) + currentOrigin += (rightButtonWidth + gapWidth) + } + + } + + } } @@ -1010,7 +1276,7 @@ class KeyboardLayout: NSObject, KeyboardKeyProtocol { let popupWidth = key.bounds.width + self.layoutConstants.popupWidthIncrement let popupHeight = totalHeight - self.layoutConstants.popupGap - key.bounds.height - let popupCenterY = 0 + //let popupCenterY = 0 return CGRectMake((key.bounds.width - popupWidth) / CGFloat(2), -popupHeight - self.layoutConstants.popupGap, popupWidth, popupHeight) } diff --git a/Keyboard/KeyboardViewController.swift b/Keyboard/KeyboardViewController.swift index c1636344..30079eef 100644 --- a/Keyboard/KeyboardViewController.swift +++ b/Keyboard/KeyboardViewController.swift @@ -3,12 +3,22 @@ // Keyboard // // Created by Alexei Baboulevitch on 6/9/14. -// Copyright (c) 2014 Alexei Baboulevitch ("Archagon"). All rights reserved. +// Copyright (c) 2014 Apple. All rights reserved. // import UIKit import AudioToolbox +enum TTDeviceType{ + case TTDeviceTypeIPhone4 + case TTDeviceTypeIPhone5 + case TTDeviceTypeIPhone6 + case TTDeviceTypeIPhone6p + +} + +var deviceType = TTDeviceType.TTDeviceTypeIPhone5 + let metrics: [String:Double] = [ "topBanner": 30 ] @@ -38,9 +48,12 @@ class KeyboardViewController: UIInputViewController { if oldValue != currentMode { setMode(currentMode) } + + forwardingView.currentMode = currentMode + forwardingView.keyboard_type = keyboard_type } } - + var backspaceActive: Bool { get { return (backspaceDelayTimer != nil) || (backspaceRepeatTimer != nil) @@ -87,7 +100,20 @@ class KeyboardViewController: UIInputViewController { self.setHeight(newValue) } } - + + //MARK:- Extra variables for extra features + var sug_word : String = "" + + var viewLongPopUp:CYRKeyboardButtonView = CYRKeyboardButtonView() + var button = CYRKeyboardButton() + + var isAllowFullAccess : Bool = false + + var keyboard_type: UIKeyboardType! + var preKeyboardType = UIKeyboardType.Default + + var key_type: Bool! + // TODO: why does the app crash if this isn't here? convenience init() { self.init(nibName: nil, bundle: nil) @@ -101,17 +127,45 @@ class KeyboardViewController: UIInputViewController { kSmallLowercase: false ]) - self.keyboard = defaultKeyboard() - - self.shiftState = .Disabled - self.currentMode = 0 - - super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) - - self.forwardingView = ForwardingView(frame: CGRectZero) - self.view.addSubview(self.forwardingView) - - NSNotificationCenter.defaultCenter().addObserver(self, selector: Selector("defaultsChanged:"), name: NSUserDefaultsDidChangeNotification, object: nil) + //self.keyboard = defaultKeyboard() + + self.shiftState = .Disabled + self.currentMode = 0 + + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + + self.forwardingView = ForwardingView(frame: CGRectZero) + self.view.addSubview(self.forwardingView) + + if let aBanner = self.createBanner() + { + + aBanner.btn1.addTarget(self, action: #selector(KeyboardViewController.didTapSuggestionButton(_:)), forControlEvents:[UIControlEvents.TouchUpInside, UIControlEvents.TouchUpOutside, UIControlEvents.TouchDragOutside]) + aBanner.btn2.addTarget(self, action: #selector(KeyboardViewController.didTapSuggestionButton(_:)), forControlEvents: [UIControlEvents.TouchUpInside, UIControlEvents.TouchUpOutside, UIControlEvents.TouchDragOutside]) + aBanner.btn3.addTarget(self, action: #selector(KeyboardViewController.didTapSuggestionButton(_:)), forControlEvents: [UIControlEvents.TouchUpInside, UIControlEvents.TouchUpOutside, UIControlEvents.TouchDragOutside]) + + + aBanner.btn1.addTarget(self, action: #selector(KeyboardViewController.didTTouchDownSuggestionButton(_:)), forControlEvents:[.TouchDown, .TouchDragInside, .TouchDragEnter]) + aBanner.btn2.addTarget(self, action: #selector(KeyboardViewController.didTTouchDownSuggestionButton(_:)), forControlEvents:[.TouchDown, .TouchDragInside, .TouchDragEnter]) + aBanner.btn3.addTarget(self, action: #selector(KeyboardViewController.didTTouchDownSuggestionButton(_:)), forControlEvents:[.TouchDown, .TouchDragInside, .TouchDragEnter]) + + aBanner.btn1.addTarget(self, action: #selector(KeyboardViewController.didTTouchExitDownSuggestionButton(_:)), forControlEvents:[.TouchDragExit, .TouchCancel]) + aBanner.btn2.addTarget(self, action: #selector(KeyboardViewController.didTTouchExitDownSuggestionButton(_:)), forControlEvents:[.TouchDragExit, .TouchCancel]) + aBanner.btn3.addTarget(self, action: #selector(KeyboardViewController.didTTouchExitDownSuggestionButton(_:)), forControlEvents:[.TouchDragExit, .TouchCancel]) + + + + aBanner.hidden = true + self.view.insertSubview(aBanner, aboveSubview: self.forwardingView) + self.bannerView = aBanner + + } + + initializePopUp() + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KeyboardViewController.defaultsChanged(_:)), name: NSUserDefaultsDidChangeNotification, object: nil) + + NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(KeyboardViewController.hideExpandView(_:)), name: "hideExpandViewNotification", object: nil) } required init?(coder: NSCoder) { @@ -126,7 +180,7 @@ class KeyboardViewController: UIInputViewController { } func defaultsChanged(notification: NSNotification) { - //let defaults = notification.object as? NSUserDefaults + _ = notification.object as? NSUserDefaults self.updateKeyCaps(self.shiftState.uppercase()) } @@ -171,6 +225,14 @@ class KeyboardViewController: UIInputViewController { var constraintsAdded: Bool = false func setupLayout() { if !constraintsAdded { + + let proxy = textDocumentProxy + self.keyboard = defaultKeyboard(proxy.keyboardType!) + + preKeyboardType = proxy.keyboardType! + + + self.layout = self.dynamicType.layoutClass.init(model: self.keyboard, superview: self.forwardingView, layoutConstants: self.dynamicType.layoutConstants, globalColors: self.dynamicType.globalColors, darkMode: self.darkMode(), solidColorMode: self.solidColorMode()) self.layout?.initialize() @@ -179,7 +241,7 @@ class KeyboardViewController: UIInputViewController { self.setupKludge() self.updateKeyCaps(self.shiftState.uppercase()) - var capsWasSet = self.setCapsIfNeeded() + _ = self.setCapsIfNeeded() self.updateAppearances(self.darkMode()) self.addInputTraitsObservers() @@ -191,8 +253,7 @@ class KeyboardViewController: UIInputViewController { // only available after frame becomes non-zero func darkMode() -> Bool { let darkMode = { () -> Bool in - let proxy = self.textDocumentProxy - return proxy.keyboardAppearance == UIKeyboardAppearance.Dark + return self.textDocumentProxy.keyboardAppearance == UIKeyboardAppearance.Dark }() return darkMode @@ -203,37 +264,48 @@ class KeyboardViewController: UIInputViewController { } var lastLayoutBounds: CGRect? - override func viewDidLayoutSubviews() { - if view.bounds == CGRectZero { - return - } - - self.setupLayout() - - let orientationSavvyBounds = CGRectMake(0, 0, self.view.bounds.width, self.heightForOrientation(self.interfaceOrientation, withTopBanner: false)) - - if (lastLayoutBounds != nil && lastLayoutBounds == orientationSavvyBounds) { - // do nothing - } - else { - let uppercase = self.shiftState.uppercase() - let characterUppercase = (NSUserDefaults.standardUserDefaults().boolForKey(kSmallLowercase) ? uppercase : true) - - self.forwardingView.frame = orientationSavvyBounds - self.layout?.layoutKeys(self.currentMode, uppercase: uppercase, characterUppercase: characterUppercase, shiftState: self.shiftState) - self.lastLayoutBounds = orientationSavvyBounds - self.setupKeys() - } - - self.bannerView?.frame = CGRectMake(0, 0, self.view.bounds.width, metric("topBanner")) - - let newOrigin = CGPointMake(0, self.view.bounds.height - self.forwardingView.bounds.height) - self.forwardingView.frame.origin = newOrigin - } - + override func viewDidLayoutSubviews() { + if view.bounds == CGRectZero { + return + } + + self.setupLayout() + + let orientationSavvyBounds = CGRectMake(0, 0, self.view.bounds.width, self.heightForOrientation(withTopBanner: false)) + + if (lastLayoutBounds != nil && lastLayoutBounds == orientationSavvyBounds) { + // do nothing + } + else { let uppercase = self.shiftState.uppercase() + let characterUppercase = (NSUserDefaults.standardUserDefaults().boolForKey(kSmallLowercase) ? uppercase : true) + + self.forwardingView.frame = orientationSavvyBounds + self.layout?.layoutKeys(self.currentMode, uppercase: uppercase, characterUppercase: characterUppercase, shiftState: self.shiftState) + self.lastLayoutBounds = orientationSavvyBounds + self.setupKeys() + } + + self.bannerView?.frame = CGRectMake(0, 0, self.view.bounds.width, metric("topBanner")) + + let proxy = textDocumentProxy + + if proxy.keyboardType == UIKeyboardType.NumberPad || proxy.keyboardType == UIKeyboardType.DecimalPad + { + self.bannerView!.hidden = true + } + else + { + self.bannerView!.hidden = false + } + + let newOrigin = CGPointMake(0, self.view.bounds.height - self.forwardingView.bounds.height) + self.forwardingView.frame.origin = newOrigin + + } + override func loadView() { super.loadView() - + if let aBanner = self.createBanner() { aBanner.hidden = true self.view.insertSubview(aBanner, belowSubview: self.forwardingView) @@ -243,9 +315,9 @@ class KeyboardViewController: UIInputViewController { override func viewWillAppear(animated: Bool) { self.bannerView?.hidden = false - self.keyboardHeight = self.heightForOrientation(self.interfaceOrientation, withTopBanner: true) + self.keyboardHeight = self.heightForOrientation(withTopBanner: true) } - + override func willRotateToInterfaceOrientation(toInterfaceOrientation: UIInterfaceOrientation, duration: NSTimeInterval) { self.forwardingView.resetTrackedViews() self.shiftStartingState = nil @@ -258,7 +330,7 @@ class KeyboardViewController: UIInputViewController { } } - self.keyboardHeight = self.heightForOrientation(toInterfaceOrientation, withTopBanner: true) + self.keyboardHeight = self.heightForOrientation(withTopBanner: true) } override func didRotateFromInterfaceOrientation(fromInterfaceOrientation: UIInterfaceOrientation) { @@ -269,78 +341,146 @@ class KeyboardViewController: UIInputViewController { } } } - - func heightForOrientation(orientation: UIInterfaceOrientation, withTopBanner: Bool) -> CGFloat { - let isPad = UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad - - //TODO: hardcoded stuff - let actualScreenWidth = (UIScreen.mainScreen().nativeBounds.size.width / UIScreen.mainScreen().nativeScale) - let canonicalPortraitHeight = (isPad ? CGFloat(264) : CGFloat(orientation.isPortrait && actualScreenWidth >= 400 ? 226 : 216)) - let canonicalLandscapeHeight = (isPad ? CGFloat(352) : CGFloat(162)) - let topBannerHeight = (withTopBanner ? metric("topBanner") : 0) - - return CGFloat(orientation.isPortrait ? canonicalPortraitHeight + topBannerHeight : canonicalLandscapeHeight + topBannerHeight) - } - + + func isCapitalalize(string: String) -> Bool + { + if string.characters.count > 0 + { + let firstChar = string[string.startIndex] + return ("A"..."Z").contains(firstChar) + } + else + { + return false + } + + } + + func hideExpandView(notification: NSNotification) + { + + if notification.userInfo != nil + { + let title = notification.userInfo!["text"] as! String + + if self.shiftState == .Enabled + { + self.textDocumentProxy.insertText(title.capitalizedString) + } + else if self.shiftState == .Locked + { + self.textDocumentProxy.insertText(title.uppercaseString) + } + else + { + self.textDocumentProxy.insertText(title) + } + + + if (isAllowFullAccess == true) + { +// isSuggestionBlank = false +// get_suggestion() +// setPredictionAndSuggestion() + } + self.setCapsIfNeeded() + + } + + if self.forwardingView.isLongPressEnable == false + { + self.view.bringSubviewToFront(self.bannerView!) + } + viewLongPopUp.hidden = true + //self.forwardingView.resetTrackedViews() + + } + + func heightForOrientation(withTopBanner withTopBanner: Bool) -> CGFloat { + let isPad = UIDevice.currentDevice().userInterfaceIdiom == UIUserInterfaceIdiom.Pad + + //TODO: hardcoded stuff + let actualScreenWidth = (UIScreen.mainScreen().nativeBounds.size.width / + UIScreen.mainScreen().nativeScale) + let isPortrait = UIScreen.mainScreen().nativeBounds.size.width < UIScreen.mainScreen().nativeBounds.size.height + + let canonicalPortraitHeight = (isPad ? CGFloat(264) : CGFloat(isPortrait && actualScreenWidth >= 400 ? 226 : 216)) + let canonicalLandscapeHeight = (isPad ? CGFloat(352) : CGFloat(162)) + + let topBannerHeight = (withTopBanner ? metric("topBanner") : 0) + let proxy = textDocumentProxy + + if proxy.keyboardType == UIKeyboardType.NumberPad || proxy.keyboardType == UIKeyboardType.DecimalPad + { + return CGFloat(isPortrait ? canonicalPortraitHeight + 0 : canonicalLandscapeHeight + 0) + } + else + { + return CGFloat(isPortrait ? canonicalPortraitHeight + topBannerHeight : canonicalLandscapeHeight + topBannerHeight) + } + + } /* BUG NOTE None of the UIContentContainer methods are called for this controller. */ - + //override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) { // super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator) //} - + func setupKeys() { if self.layout == nil { return } - + for page in keyboard.pages { for rowKeys in page.rows { // TODO: quick hack for key in rowKeys { if let keyView = self.layout?.viewForKey(key) { keyView.removeTarget(nil, action: nil, forControlEvents: UIControlEvents.AllEvents) - + switch key.type { case Key.KeyType.KeyboardChange: - keyView.addTarget(self, action: "advanceTapped:", forControlEvents: .TouchUpInside) + keyView.addTarget(self, action: #selector(KeyboardViewController.advanceTapped(_:)), forControlEvents: .TouchUpInside) case Key.KeyType.Backspace: let cancelEvents: UIControlEvents = [UIControlEvents.TouchUpInside, UIControlEvents.TouchUpInside, UIControlEvents.TouchDragExit, UIControlEvents.TouchUpOutside, UIControlEvents.TouchCancel, UIControlEvents.TouchDragOutside] - keyView.addTarget(self, action: "backspaceDown:", forControlEvents: .TouchDown) - keyView.addTarget(self, action: "backspaceUp:", forControlEvents: cancelEvents) + keyView.addTarget(self, action: #selector(KeyboardViewController.backspaceDown(_:)), forControlEvents: .TouchDown) + keyView.addTarget(self, action: #selector(KeyboardViewController.backspaceUp(_:)), forControlEvents: cancelEvents) case Key.KeyType.Shift: - keyView.addTarget(self, action: Selector("shiftDown:"), forControlEvents: .TouchDown) - keyView.addTarget(self, action: Selector("shiftUp:"), forControlEvents: .TouchUpInside) - keyView.addTarget(self, action: Selector("shiftDoubleTapped:"), forControlEvents: .TouchDownRepeat) + keyView.addTarget(self, action: #selector(KeyboardViewController.shiftDown(_:)), forControlEvents: .TouchDown) + keyView.addTarget(self, action: #selector(KeyboardViewController.shiftUp(_:)), forControlEvents: .TouchUpInside) + keyView.addTarget(self, action: #selector(KeyboardViewController.shiftDoubleTapped(_:)), forControlEvents: .TouchDownRepeat) case Key.KeyType.ModeChange: - keyView.addTarget(self, action: Selector("modeChangeTapped:"), forControlEvents: .TouchDown) + keyView.addTarget(self, action: #selector(KeyboardViewController.modeChangeTapped(_:)), forControlEvents: .TouchDown) case Key.KeyType.Settings: - keyView.addTarget(self, action: Selector("toggleSettings"), forControlEvents: .TouchUpInside) + keyView.addTarget(self, action: #selector(KeyboardViewController.toggleSettings), forControlEvents: .TouchUpInside) default: break } if key.isCharacter { if UIDevice.currentDevice().userInterfaceIdiom != UIUserInterfaceIdiom.Pad { - keyView.addTarget(self, action: Selector("showPopup:"), forControlEvents: [.TouchDown, .TouchDragInside, .TouchDragEnter]) - keyView.addTarget(keyView, action: Selector("hidePopup"), forControlEvents: [.TouchDragExit, .TouchCancel]) - keyView.addTarget(self, action: Selector("hidePopupDelay:"), forControlEvents: [.TouchUpInside, .TouchUpOutside, .TouchDragOutside]) + keyView.addTarget(self, action: #selector(KeyboardViewController.showPopup(_:)), forControlEvents: [.TouchDown, .TouchDragInside, .TouchDragEnter]) + keyView.addTarget(keyView, action: #selector(keyView.hidePopup), forControlEvents: [.TouchDragExit, .TouchCancel]) + keyView.addTarget(self, action: #selector(KeyboardViewController.hidePopupDelay(_:)), forControlEvents: [.TouchUpInside, .TouchUpOutside, .TouchDragOutside]) } + + keyView.addTarget(self, action: #selector(KeyboardViewController.keyCharDoubleTapped(_:)), forControlEvents: .TouchDownRepeat) } if key.hasOutput { - keyView.addTarget(self, action: "keyPressedHelper:", forControlEvents: .TouchUpInside) + keyView.addTarget(self, action: #selector(KeyboardViewController.keyPressedHelper(_:)), forControlEvents: .TouchUpInside) } if key.type != Key.KeyType.Shift && key.type != Key.KeyType.ModeChange { - keyView.addTarget(self, action: Selector("highlightKey:"), forControlEvents: [.TouchDown, .TouchDragInside, .TouchDragEnter]) - keyView.addTarget(self, action: Selector("unHighlightKey:"), forControlEvents: [.TouchUpInside, .TouchUpOutside, .TouchDragOutside, .TouchDragExit, .TouchCancel]) + keyView.addTarget(self, action: #selector(KeyboardViewController.highlightKey(_:)), forControlEvents: [.TouchDown, .TouchDragInside, .TouchDragEnter]) + keyView.addTarget(self, action: #selector(KeyboardViewController.unHighlightKey(_:)), forControlEvents: [.TouchUpInside, .TouchUpOutside, .TouchDragOutside, .TouchDragExit, .TouchCancel]) } - keyView.addTarget(self, action: Selector("playKeySound"), forControlEvents: .TouchDown) + keyView.addTarget(self, action: #selector(KeyboardViewController.playKeySound), forControlEvents: .TouchDown) } } } @@ -358,9 +498,20 @@ class KeyboardViewController: UIInputViewController { if sender == self.keyWithDelayedPopup { self.popupDelayTimer?.invalidate() } - sender.showPopup() + + self.view.sendSubviewToBack(self.bannerView!) + + let proxy = textDocumentProxy + if proxy.keyboardType == UIKeyboardType.NumberPad || proxy.keyboardType == UIKeyboardType.DecimalPad + { + + } + else + { + sender.showPopup() + } } - + func hidePopupDelay(sender: KeyboardKey) { self.popupDelayTimer?.invalidate() @@ -370,7 +521,7 @@ class KeyboardViewController: UIInputViewController { } if sender.popup != nil { - self.popupDelayTimer = NSTimer.scheduledTimerWithTimeInterval(0.05, target: self, selector: Selector("hidePopupCallback"), userInfo: nil, repeats: false) + self.popupDelayTimer = NSTimer.scheduledTimerWithTimeInterval(0.05, target: self, selector: #selector(KeyboardViewController.hidePopupCallback), userInfo: nil, repeats: false) } } @@ -390,15 +541,65 @@ class KeyboardViewController: UIInputViewController { } // TODO: this is currently not working as intended; only called when selection changed -- iOS bug - override func textDidChange(textInput: UITextInput?) { - self.contextChanged() - } - + override func textDidChange(textInput: UITextInput?) { + self.contextChanged() + + let proxy = textDocumentProxy + + keyboard_type = proxy.keyboardType! + + getKeyboardType() + + if (proxy.documentContextBeforeInput) != nil + { + if isAllowFullAccess == true + { + + } + + } + else + { + sug_word = " " + + } + + dispatch_async(dispatch_get_main_queue(), { + if proxy.keyboardType! != self.preKeyboardType + { + self.forwardingView.resetTrackedViews() + self.shiftStartingState = nil + self.shiftWasMultitapped = false + // + // optimization: ensures smooth animation + if let keyPool = self.layout?.keyPool { + for view1 in keyPool { + view1.shouldRasterize = true + } + } + + for (_, view1) in self.forwardingView.subviews.enumerate() + { + let v = view1 + v.removeFromSuperview() + + } + + self.keyboardHeight = self.heightForOrientation(withTopBanner: true) + + self.constraintsAdded = false + self.setupLayout() + + } + + }) + } + func contextChanged() { self.setCapsIfNeeded() self.autoPeriodState = .NoSpace } - + func setHeight(height: CGFloat) { if self.heightConstraint == nil { self.heightConstraint = NSLayoutConstraint( @@ -410,7 +611,7 @@ class KeyboardViewController: UIInputViewController { multiplier:0, constant:height) self.heightConstraint!.priority = 1000 - + self.view.addConstraint(self.heightConstraint!) // TODO: what if view already has constraint added? } else { @@ -453,33 +654,36 @@ class KeyboardViewController: UIInputViewController { // auto period on double space // TODO: timeout + // var lastCharCountInBeforeContext: Int = 0 + // var readyForDoubleSpacePeriod: Bool = true + self.handleAutoPeriod(model) // TODO: reset context } self.setCapsIfNeeded() } - + func handleAutoPeriod(key: Key) { if !NSUserDefaults.standardUserDefaults().boolForKey(kPeriodShortcut) { return } - + if self.autoPeriodState == .FirstSpace { if key.type != Key.KeyType.Space { self.autoPeriodState = .NoSpace return } - + let charactersAreInCorrectState = { () -> Bool in let previousContext = self.textDocumentProxy.documentContextBeforeInput - + if previousContext == nil || (previousContext!).characters.count < 3 { return false } - + var index = previousContext!.endIndex - + index = index.predecessor() if previousContext![index] != " " { return false @@ -529,7 +733,7 @@ class KeyboardViewController: UIInputViewController { self.setCapsIfNeeded() // trigger for subsequent deletes - self.backspaceDelayTimer = NSTimer.scheduledTimerWithTimeInterval(backspaceDelay - backspaceRepeat, target: self, selector: Selector("backspaceDelayCallback"), userInfo: nil, repeats: false) + self.backspaceDelayTimer = NSTimer.scheduledTimerWithTimeInterval(backspaceDelay - backspaceRepeat, target: self, selector: #selector(KeyboardViewController.backspaceDelayCallback), userInfo: nil, repeats: false) } func backspaceUp(sender: KeyboardKey) { @@ -538,7 +742,7 @@ class KeyboardViewController: UIInputViewController { func backspaceDelayCallback() { self.backspaceDelayTimer = nil - self.backspaceRepeatTimer = NSTimer.scheduledTimerWithTimeInterval(backspaceRepeat, target: self, selector: Selector("backspaceRepeatCallback"), userInfo: nil, repeats: true) + self.backspaceRepeatTimer = NSTimer.scheduledTimerWithTimeInterval(backspaceRepeat, target: self, selector: #selector(KeyboardViewController.backspaceRepeatCallback), userInfo: nil, repeats: true) } func backspaceRepeatCallback() { @@ -731,63 +935,61 @@ class KeyboardViewController: UIInputViewController { if !NSUserDefaults.standardUserDefaults().boolForKey(kAutoCapitalization) { return false } - - let traits = self.textDocumentProxy - if let autocapitalization = traits.autocapitalizationType { - let documentProxy = self.textDocumentProxy - //var beforeContext = documentProxy.documentContextBeforeInput - - switch autocapitalization { - case .None: - return false - case .Words: - if let beforeContext = documentProxy.documentContextBeforeInput { - let previousCharacter = beforeContext[beforeContext.endIndex.predecessor()] - return self.characterIsWhitespace(previousCharacter) - } - else { - return true - } - - case .Sentences: - if let beforeContext = documentProxy.documentContextBeforeInput { - let offset = min(3, beforeContext.characters.count) - var index = beforeContext.endIndex - - for (var i = 0; i < offset; i += 1) { - index = index.predecessor() - let char = beforeContext[index] + + if let autocapitalization = self.textDocumentProxy.autocapitalizationType { + var _ = self.textDocumentProxy.documentContextBeforeInput + + switch autocapitalization { + case .None: + return false + case .Words: + if let beforeContext = self.textDocumentProxy.documentContextBeforeInput { + let previousCharacter = beforeContext[beforeContext.endIndex.predecessor()] + return self.characterIsWhitespace(previousCharacter) + } + else { + return true + } + + case .Sentences: + if let beforeContext = self.textDocumentProxy.documentContextBeforeInput { + let offset = min(3, beforeContext.characters.count) + var index = beforeContext.endIndex - if characterIsPunctuation(char) { - if i == 0 { - return false //not enough spaces after punctuation + for i in 0 ..< offset { + index = index.predecessor() + let char = beforeContext[index] + + if characterIsPunctuation(char) { + if i == 0 { + return false //not enough spaces after punctuation + } + else { + return true //punctuation with at least one space after it + } } else { - return true //punctuation with at least one space after it - } - } - else { - if !characterIsWhitespace(char) { - return false //hit a foreign character before getting to 3 spaces - } - else if characterIsNewline(char) { - return true //hit start of line + if !characterIsWhitespace(char) { + return false //hit a foreign character before getting to 3 spaces + } + else if characterIsNewline(char) { + return true //hit start of line + } } } + + return true //either got 3 spaces or hit start of line } - - return true //either got 3 spaces or hit start of line - } - else { + else { + return true + } + case .AllCharacters: return true } - case .AllCharacters: - return true } - } - else { - return false - } + else { + return false + } } // this only works if full access is enabled @@ -810,7 +1012,7 @@ class KeyboardViewController: UIInputViewController { class var globalColors: GlobalColors.Type { get { return GlobalColors.self }} func keyPressed(key: Key) { - self.textDocumentProxy.insertText(key.outputForCase(self.shiftState.uppercase())) + self.textDocumentProxy.insertText(key.outputForCase(self.shiftState.uppercase())) } // a banner that sits in the empty space on top of the keyboard @@ -824,7 +1026,471 @@ class KeyboardViewController: UIInputViewController { func createSettings() -> ExtraView? { // note that dark mode is not yet valid here, so we just put false for clarity let settingsView = DefaultSettings(globalColors: self.dynamicType.globalColors, darkMode: false, solidColorMode: self.solidColorMode()) - settingsView.backButton?.addTarget(self, action: Selector("toggleSettings"), forControlEvents: UIControlEvents.TouchUpInside) + settingsView.backButton?.addTarget(self, action: #selector(KeyboardViewController.toggleSettings), forControlEvents: UIControlEvents.TouchUpInside) return settingsView } + + // MARK: Added methods for extra features + func initializePopUp() + { + button.hidden = true + button.forwordingView = forwardingView + button.frame = CGRectMake(0, 0, 20, 20) + button.tag = 111 + self.view.insertSubview(self.button, aboveSubview: self.forwardingView) + button.setupInputOptionsConfigurationWithView(forwardingView) + button.hidden = true + viewLongPopUp.hidden = true + } + + func didTTouchExitDownSuggestionButton(sender: AnyObject?) + { + let button = sender as! UIButton + + button.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + + button.setTitleColor(UIColor.whiteColor(), forState: .Normal) + + } + + func didTTouchDownSuggestionButton(sender: AnyObject?) + { + let button = sender as! UIButton + + if let btn_title = button.titleForState(UIControlState.Normal) + { + let title = btn_title.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + + if(title.characters.count != 0) + { + button.backgroundColor = UIColor(red:0.92, green:0.93, blue:0.94, alpha:1) + button.setTitleColor(UIColor.blackColor(), forState: .Normal) + } + } + } + + + func didTapSuggestionButton(sender: AnyObject?) + { + + self.currentMode = 0 + + _ = sender as! UIButton + + self.autoPeriodState = .FirstSpace + + var title1 = self.bannerView!.btn1.titleForState(.Normal) + var title2 = self.bannerView!.btn2.titleForState(.Normal) + var title3 = self.bannerView!.btn3.titleForState(.Normal) + + title1 = title1!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + title2 = title2!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + title3 = title3!.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + + onSuggestionTap(sender) + + self.bannerView!.btn1.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + self.bannerView!.btn2.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + self.bannerView!.btn3.backgroundColor = UIColor(red:0.68, green:0.71, blue:0.74, alpha:1) + + self.bannerView!.btn1.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.bannerView!.btn2.setTitleColor(UIColor.whiteColor(), forState: .Normal) + self.bannerView!.btn3.setTitleColor(UIColor.whiteColor(), forState: .Normal) + + + self.setCapsIfNeeded() + + } + + func onSuggestionTap(sender: AnyObject?) + { + + let button = sender as! UIButton + + let proxy = self.textDocumentProxy + if let titleBtn = button.titleForState(.Normal) + { + let title = titleBtn.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) + + if title.characters.count == 0 + { + return + } + let tokens = self.sug_word.componentsSeparatedByCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet()) as [String] + + if let lastWord = tokens.last + { + if lastWord.characters.count != 0 + { + if title.characters.count == 0 + { + + } + else + { + for _ in lastWord.characters + { + proxy.deleteBackward() + } + + } + + } + } + + if self.shiftState == .Enabled + { + proxy.insertText(title.capitalizedString+" ") + } + else if self.shiftState == .Locked + { + proxy.insertText(title.uppercaseString+" ") + } + else + { + if let lastWord = tokens.last + { + if lastWord.characters.count > 0 + { + if self.isCapitalalize(tokens.last!) + { + proxy.insertText(title.capitalizedString+" ") + } + else + { + proxy.insertText(title+" ") + } + } + else + { + proxy.insertText(title+" ") + } + + + } + else + { + proxy.insertText(title+" ") + } + + } + + if button == self.bannerView!.btn2 + { + let titleBtn1 = self.bannerView!.btn1.titleForState(.Normal) + let titleBtn3 = self.bannerView!.btn3.titleForState(.Normal) + + if (titleBtn1!).characters.count == 0 && (titleBtn3!).characters.count == 0 + { + } + } + + } + } + + + + func keyCharDoubleTapped(sender: KeyboardKey) + { + if sender.tag == 888 + { + sender.hidePopup() + + var arrOptions = self.getInputOption(sender.text.uppercaseString) as [String] + + if arrOptions.count > 0 + { + if arrOptions[0].characters.count > 0 + { + var offsetY : CGFloat = 9 + let isLandscape = UIScreen.mainScreen().nativeBounds.size.width > UIScreen.mainScreen().nativeBounds.size.height + + if KeyboardViewController.getDeviceType() == TTDeviceType.TTDeviceTypeIPhone4 + { + offsetY = 9 + if isLandscape + { + offsetY = 3 + } + } + else if KeyboardViewController.getDeviceType() == TTDeviceType.TTDeviceTypeIPhone5 + { + offsetY = 9 + if isLandscape + { + offsetY = 3 + } + + } + else if KeyboardViewController.getDeviceType() == TTDeviceType.TTDeviceTypeIPhone6 + { + offsetY = 13 + if isLandscape + { + offsetY = 3 + } + + } + else if KeyboardViewController.getDeviceType() == TTDeviceType.TTDeviceTypeIPhone6p + { + offsetY = 16 + if isLandscape + { + offsetY = 3 + } + } + + self.button.removeFromSuperview() + + self.button.frame = CGRectMake(sender.frame.origin.x, sender.frame.origin.y + sender.frame.size.height - offsetY, sender.frame.size.width, sender.frame.size.height) + + // self.button.frame = CGRectMake(sender.frame.origin.x, sender.frame.origin.y , sender.frame.size.width, sender.frame.size.height) + + self.view.insertSubview(self.button, aboveSubview: self.forwardingView) + + self.viewLongPopUp = self.button.showLongPopUpOptions() + self.button.input = sender.text + self.button.hidden = true + self.button.inputOptions = arrOptions + self.viewLongPopUp.hidden = false + + for anyView in self.view.subviews + { + if anyView is CYRKeyboardButtonView + { + anyView.removeFromSuperview() + } + } + + self.viewLongPopUp.userInteractionEnabled = false; + + button.setupInputOptionsConfigurationWithView(forwardingView) + self.view.insertSubview(self.viewLongPopUp, aboveSubview: self.forwardingView) + self.forwardingView.isLongPressEnable = true + self.view.bringSubviewToFront(self.viewLongPopUp) + //self.forwardingView.resetTrackedViews() + //sender.hidePopup() + //self.view.addSubview(self.viewLongPopUp) + + sender.tag = 0 + } + } + } + } + + class func getDeviceType()->TTDeviceType + { + var height = UIScreen.mainScreen().bounds.size.height + + if UIScreen.mainScreen().bounds.size.height < UIScreen.mainScreen().bounds.size.width + { + height = UIScreen.mainScreen().bounds.size.width + } + + switch (height) { + case 480: + deviceType = TTDeviceType.TTDeviceTypeIPhone4 ; + break; + + case 568: + deviceType = TTDeviceType.TTDeviceTypeIPhone5 ; + break; + case 667: + deviceType = TTDeviceType.TTDeviceTypeIPhone6 ; + break; + case 736: + deviceType = TTDeviceType.TTDeviceTypeIPhone6p ; + break; + + default: + break; + } + + return deviceType + + } + + func getInputOption(strChar : String) -> [String] + { + + if strChar == "A" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["A","Á","À","Ä","Â","Ã","Å","Æ","Ā"] //"ª", "Ą" + } + else + { + return ["a","á", "à", "ä", "â", "ã", "å", "æ","ā"] //"ą" + } + + } + else if strChar == "." + { + + return [".com",".edu",".net",".org"] //"ą + + } + else if strChar == "E" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["E","É","È","Ë","Ê","Ę","Ė","Ē"] + } + else + { + return ["e", "é", "è", "ë", "ê", "ę", "ė", "ē"] + } + + } + else if strChar == "U" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["U","Ú","Ü","Ù","Û"] + } + else + { + return ["u", "ú", "ü", "ù", "û", "ū"] + } + + } + else if strChar == "I" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["I","Í","Ï","Ì","Î","Į","Ī"] + } + else + { + return ["i", "í", "ï", "ì", "î", "į", "ī"] + } + + } + else if strChar == "O" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["O","Ó","Ò","Ö","Ô","Õ","Ø","Œ","Ō"] //"º" + } + else + { + return ["o", "ó", "ò", "ö", "ô", "õ", "ø", "œ", "ō"] + } + + } + else if strChar == "S" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["S","Š"] + } + else + { + return ["s","š"] + } + + } + else if strChar == "D" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["D","Đ"] + } + else + { + return ["d", "đ"] + } + + } + else if strChar == "C" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["C","Ç","Ć","Č"] + } + else + { + return ["c", "ç", "ć", "č"] + } + + } + else if strChar == "N" + { + if self.shiftState == .Enabled || self.shiftState == .Locked + { + return ["N","Ñ","Ń"] + } + else + { + return ["n","ñ", "ń"] + } + + } + return [""] + } + + func getKeyboardType() + { + let proxy = textDocumentProxy + + if proxy.keyboardType == UIKeyboardType.EmailAddress + { + //add code here to display number/decimal input keyboard + key_type = true + + } + else if(proxy.keyboardType == UIKeyboardType.WebSearch) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.ASCIICapable) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.NumbersAndPunctuation) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.URL) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.NumberPad) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.DecimalPad) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.NamePhonePad) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.Twitter) + { + key_type = true + } + else if(proxy.keyboardType == UIKeyboardType.Default) + { + + if(proxy.autocorrectionType == UITextAutocorrectionType.No) + { + key_type = true + } + else + { + key_type = false + } + + } + else + { + key_type = false + } + + } + + } diff --git a/Keyboard/Shapes.swift b/Keyboard/Shapes.swift index d46d4c8e..0683a4e8 100644 --- a/Keyboard/Shapes.swift +++ b/Keyboard/Shapes.swift @@ -64,7 +64,7 @@ class Shape: UIView { self.addSubview(self.overflowCanvas) } - required init(coder aDecoder: NSCoder) { + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } @@ -104,7 +104,7 @@ class Shape: UIView { self.opaque = false } - required init(coder aDecoder: NSCoder) { + required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } diff --git a/TastyImitationKeyboard.xcodeproj/project.pbxproj b/TastyImitationKeyboard.xcodeproj/project.pbxproj index cea7a020..09881144 100644 --- a/TastyImitationKeyboard.xcodeproj/project.pbxproj +++ b/TastyImitationKeyboard.xcodeproj/project.pbxproj @@ -25,17 +25,20 @@ 4E8EF39919F95D75009CBF5D /* KeyboardFramework.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 4E8EF38119F95D74009CBF5D /* KeyboardFramework.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 4E8EF3A019F95D93009CBF5D /* KeyboardFramework.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4E8EF38119F95D74009CBF5D /* KeyboardFramework.framework */; }; 4EC2A46D19DF811E00F789E1 /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC2A46919DF811E00F789E1 /* KeyboardViewController.swift */; }; - 4EC2A46E19DF811E00F789E1 /* KeyboardLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC2A46A19DF811E00F789E1 /* KeyboardLayout.swift */; }; 4EC2A47019DF811E00F789E1 /* ForwardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EC2A46C19DF811E00F789E1 /* ForwardingView.swift */; }; - 4ECBD90219F16DC7004FA2A3 /* DefaultKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ECBD90119F16DC7004FA2A3 /* DefaultKeyboard.swift */; }; 4EE7599B19F75A0D00B4E6ED /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE7599A19F75A0D00B4E6ED /* Utilities.swift */; }; - 4EEFD78919E0DC6B004D4974 /* CatboardBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EEFD78819E0DC6B004D4974 /* CatboardBanner.swift */; }; 4EEFD78B19E0DF15004D4974 /* Shapes.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EEFD78A19E0DF15004D4974 /* Shapes.swift */; }; 4EF16F9119D254E00076AFCB /* Background.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 4EF16F9019D254E00076AFCB /* Background.jpg */; }; 4EF16F9619D255030076AFCB /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 4EF16F9319D255030076AFCB /* Images.xcassets */; }; 4EF16F9819D255030076AFCB /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF16F9519D255030076AFCB /* ViewController.swift */; }; 4EF16F9B19D2550D0076AFCB /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EF16F9A19D2550D0076AFCB /* AppDelegate.swift */; }; 4EF16F9F19D2552E0076AFCB /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4EF16F9D19D2552E0076AFCB /* Main.storyboard */; }; + 82FD1A801B0B2C2E00A6D23D /* CatboardBanner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82FD1A7F1B0B2C2E00A6D23D /* CatboardBanner.swift */; }; + 82FD1A861B0B319100A6D23D /* CYRKeyboardButton.m in Sources */ = {isa = PBXBuildFile; fileRef = 82FD1A831B0B319100A6D23D /* CYRKeyboardButton.m */; }; + 82FD1A871B0B319100A6D23D /* CYRKeyboardButtonView.m in Sources */ = {isa = PBXBuildFile; fileRef = 82FD1A851B0B319100A6D23D /* CYRKeyboardButtonView.m */; }; + 82FD1A8A1B0B31A300A6D23D /* TurtleBezierPath.m in Sources */ = {isa = PBXBuildFile; fileRef = 82FD1A891B0B31A300A6D23D /* TurtleBezierPath.m */; }; + 82FD1A911B0B3C8D00A6D23D /* DefaultKeyboard.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82FD1A901B0B3C8D00A6D23D /* DefaultKeyboard.swift */; }; + 82FD1A931B0B3D3800A6D23D /* KeyboardLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82FD1A921B0B3D3800A6D23D /* KeyboardLayout.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -116,11 +119,8 @@ 4E8EF38419F95D75009CBF5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 4E8EF38519F95D75009CBF5D /* KeyboardFramework.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KeyboardFramework.h; sourceTree = ""; }; 4EC2A46919DF811E00F789E1 /* KeyboardViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardViewController.swift; sourceTree = ""; }; - 4EC2A46A19DF811E00F789E1 /* KeyboardLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardLayout.swift; sourceTree = ""; }; 4EC2A46C19DF811E00F789E1 /* ForwardingView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForwardingView.swift; sourceTree = ""; }; - 4ECBD90119F16DC7004FA2A3 /* DefaultKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultKeyboard.swift; sourceTree = ""; }; 4EE7599A19F75A0D00B4E6ED /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Utilities.swift; sourceTree = ""; }; - 4EEFD78819E0DC6B004D4974 /* CatboardBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CatboardBanner.swift; sourceTree = ""; }; 4EEFD78A19E0DF15004D4974 /* Shapes.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Shapes.swift; sourceTree = ""; }; 4EF16F9019D254E00076AFCB /* Background.jpg */ = {isa = PBXFileReference; lastKnownFileType = image.jpeg; path = Background.jpg; sourceTree = ""; }; 4EF16F9219D254EA0076AFCB /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -128,6 +128,16 @@ 4EF16F9519D255030076AFCB /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 4EF16F9A19D2550D0076AFCB /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 4EF16F9E19D2552E0076AFCB /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Main.storyboard; sourceTree = ""; }; + 82FD1A7F1B0B2C2E00A6D23D /* CatboardBanner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CatboardBanner.swift; sourceTree = ""; }; + 82FD1A821B0B319100A6D23D /* CYRKeyboardButton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYRKeyboardButton.h; sourceTree = ""; }; + 82FD1A831B0B319100A6D23D /* CYRKeyboardButton.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYRKeyboardButton.m; sourceTree = ""; }; + 82FD1A841B0B319100A6D23D /* CYRKeyboardButtonView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CYRKeyboardButtonView.h; sourceTree = ""; }; + 82FD1A851B0B319100A6D23D /* CYRKeyboardButtonView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CYRKeyboardButtonView.m; sourceTree = ""; }; + 82FD1A881B0B31A300A6D23D /* TurtleBezierPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TurtleBezierPath.h; sourceTree = ""; }; + 82FD1A891B0B31A300A6D23D /* TurtleBezierPath.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TurtleBezierPath.m; sourceTree = ""; }; + 82FD1A8C1B0B31F900A6D23D /* Keyboard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Keyboard-Bridging-Header.h"; sourceTree = ""; }; + 82FD1A901B0B3C8D00A6D23D /* DefaultKeyboard.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DefaultKeyboard.swift; sourceTree = ""; }; + 82FD1A921B0B3D3800A6D23D /* KeyboardLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardLayout.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -176,7 +186,7 @@ isa = PBXGroup; children = ( 4E5B67A1196E03B700114361 /* KeyboardModel.swift */, - 4ECBD90119F16DC7004FA2A3 /* DefaultKeyboard.swift */, + 82FD1A901B0B3C8D00A6D23D /* DefaultKeyboard.swift */, 4E60A13D1979FB2E00854CC8 /* DirectionEnum.swift */, ); name = Model; @@ -186,8 +196,8 @@ isa = PBXGroup; children = ( 4EC2A46919DF811E00F789E1 /* KeyboardViewController.swift */, + 82FD1A921B0B3D3800A6D23D /* KeyboardLayout.swift */, 4E3B5A931A0654A8003366F6 /* KeyboardInputTraits.swift */, - 4EC2A46A19DF811E00F789E1 /* KeyboardLayout.swift */, 4EC2A46C19DF811E00F789E1 /* ForwardingView.swift */, ); name = Controller; @@ -197,7 +207,7 @@ isa = PBXGroup; children = ( 4E6AEE4B19D246D700931E8F /* Catboard.swift */, - 4EEFD78819E0DC6B004D4974 /* CatboardBanner.swift */, + 82FD1A7F1B0B2C2E00A6D23D /* CatboardBanner.swift */, ); name = Demo; sourceTree = ""; @@ -264,6 +274,9 @@ 4E807DBA19461DC700D875D1 /* Keyboard */ = { isa = PBXGroup; children = ( + 82FD1A8C1B0B31F900A6D23D /* Keyboard-Bridging-Header.h */, + 82FD1A811B0B319100A6D23D /* CYRKeyboardButton */, + 82FD1A8B1B0B31B400A6D23D /* Library */, 4E6AEE5219D2488B00931E8F /* Controller */, 4E6AEE5019D2486900931E8F /* Model */, 4E6AEE4F19D2484B00931E8F /* Views */, @@ -308,6 +321,26 @@ name = Utility; sourceTree = ""; }; + 82FD1A811B0B319100A6D23D /* CYRKeyboardButton */ = { + isa = PBXGroup; + children = ( + 82FD1A881B0B31A300A6D23D /* TurtleBezierPath.h */, + 82FD1A891B0B31A300A6D23D /* TurtleBezierPath.m */, + 82FD1A821B0B319100A6D23D /* CYRKeyboardButton.h */, + 82FD1A831B0B319100A6D23D /* CYRKeyboardButton.m */, + 82FD1A841B0B319100A6D23D /* CYRKeyboardButtonView.h */, + 82FD1A851B0B319100A6D23D /* CYRKeyboardButtonView.m */, + ); + path = CYRKeyboardButton; + sourceTree = ""; + }; + 82FD1A8B1B0B31B400A6D23D /* Library */ = { + isa = PBXGroup; + children = ( + ); + name = Library; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -386,7 +419,7 @@ 4E807D8B19461D9000D875D1 /* Project object */ = { isa = PBXProject; attributes = { - LastSwiftMigration = 0710; + LastSwiftMigration = 0730; LastSwiftUpdateCheck = 0710; LastUpgradeCheck = 0710; ORGANIZATIONNAME = Apple; @@ -467,21 +500,24 @@ files = ( 4E52A6D21A06A61F006A08CE /* ImageKey.swift in Sources */, 4E52A6D41A06A626006A08CE /* ExtraView.swift in Sources */, + 82FD1A931B0B3D3800A6D23D /* KeyboardLayout.swift in Sources */, 4EC2A47019DF811E00F789E1 /* ForwardingView.swift in Sources */, - 4EC2A46E19DF811E00F789E1 /* KeyboardLayout.swift in Sources */, + 82FD1A801B0B2C2E00A6D23D /* CatboardBanner.swift in Sources */, 4E60A13A1979FA5C00854CC8 /* KeyboardKeyBackground.swift in Sources */, + 82FD1A911B0B3C8D00A6D23D /* DefaultKeyboard.swift in Sources */, 4E5B67A2196E03B700114361 /* KeyboardModel.swift in Sources */, 4E60A13C1979FA8E00854CC8 /* KeyboardConnector.swift in Sources */, 4E00A6E5197183EE009414F2 /* KeyboardKey.swift in Sources */, - 4EEFD78919E0DC6B004D4974 /* CatboardBanner.swift in Sources */, 4EE7599B19F75A0D00B4E6ED /* Utilities.swift in Sources */, 4EEFD78B19E0DF15004D4974 /* Shapes.swift in Sources */, - 4ECBD90219F16DC7004FA2A3 /* DefaultKeyboard.swift in Sources */, 4E3B5A941A0654A8003366F6 /* KeyboardInputTraits.swift in Sources */, 4E52A6D81A06C16C006A08CE /* DefaultSettings.swift in Sources */, 4E72C96819E04A7A00DFDDB0 /* Catboard.swift in Sources */, + 82FD1A861B0B319100A6D23D /* CYRKeyboardButton.m in Sources */, 4E60A13E1979FB2E00854CC8 /* DirectionEnum.swift in Sources */, 4EC2A46D19DF811E00F789E1 /* KeyboardViewController.swift in Sources */, + 82FD1A871B0B319100A6D23D /* CYRKeyboardButtonView.m in Sources */, + 82FD1A8A1B0B31A300A6D23D /* TurtleBezierPath.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -617,9 +653,11 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = HostingApp/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Archagon.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ""; }; name = Debug; }; @@ -630,9 +668,11 @@ ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; EMBEDDED_CONTENT_CONTAINS_SWIFT = YES; INFOPLIST_FILE = HostingApp/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "Archagon.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = ""; }; name = Release; }; @@ -645,6 +685,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "Archagon.HostingApp.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Keyboard; SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/Keyboard/Keyboard-Bridging-Header.h"; }; name = Debug; }; @@ -657,6 +698,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "Archagon.HostingApp.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = Keyboard; SKIP_INSTALL = YES; + SWIFT_OBJC_BRIDGING_HEADER = "$(SRCROOT)/Keyboard/Keyboard-Bridging-Header.h"; }; name = Release; };