http://git-wip-us.apache.org/repos/asf/usergrid/blob/7442c881/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextView.m
----------------------------------------------------------------------
diff --git 
a/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextView.m
 
b/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextView.m
new file mode 100644
index 0000000..a1433b7
--- /dev/null
+++ 
b/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextView.m
@@ -0,0 +1,1117 @@
+//
+//   Copyright 2014 Slack Technologies, Inc.
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//
+
+#import "SLKTextView.h"
+
+#import "SLKTextView+SLKAdditions.h"
+
+#import "SLKUIConstants.h"
+
+NSString * const SLKTextViewTextWillChangeNotification =            
@"SLKTextViewTextWillChangeNotification";
+NSString * const SLKTextViewContentSizeDidChangeNotification =      
@"SLKTextViewContentSizeDidChangeNotification";
+NSString * const SLKTextViewSelectedRangeDidChangeNotification =    
@"SLKTextViewSelectedRangeDidChangeNotification";
+NSString * const SLKTextViewDidPasteItemNotification =              
@"SLKTextViewDidPasteItemNotification";
+NSString * const SLKTextViewDidShakeNotification =                  
@"SLKTextViewDidShakeNotification";
+
+NSString * const SLKTextViewPastedItemContentType =                 
@"SLKTextViewPastedItemContentType";
+NSString * const SLKTextViewPastedItemMediaType =                   
@"SLKTextViewPastedItemMediaType";
+NSString * const SLKTextViewPastedItemData =                        
@"SLKTextViewPastedItemData";
+
+static NSString *const SLKTextViewGenericFormattingSelectorPrefix = 
@"slk_format_";
+
+@interface SLKTextView ()
+
+// The label used as placeholder
+@property (nonatomic, strong) UILabel *placeholderLabel;
+
+// The initial font point size, used for dynamic type calculations
+@property (nonatomic) CGFloat initialFontSize;
+
+// The keyboard commands available for external keyboards
+@property (nonatomic, strong) NSArray *keyboardCommands;
+
+// Used for moving the caret up/down
+@property (nonatomic) UITextLayoutDirection verticalMoveDirection;
+@property (nonatomic) CGRect verticalMoveStartCaretRect;
+@property (nonatomic) CGRect verticalMoveLastCaretRect;
+
+// Used for detecting if the scroll indicator was previously flashed
+@property (nonatomic) BOOL didFlashScrollIndicators;
+
+@property (nonatomic, strong) NSMutableArray *registeredFormattingTitles;
+@property (nonatomic, strong) NSMutableArray *registeredFormattingSymbols;
+@property (nonatomic, getter=isFormatting) BOOL formatting;
+
+@end
+
+@implementation SLKTextView
+@synthesize delegate = _delegate;
+
+#pragma mark - Initialization
+
+- (instancetype)initWithFrame:(CGRect)frame textContainer:(NSTextContainer 
*)textContainer
+{
+    if (self = [super initWithFrame:frame textContainer:textContainer]) {
+        [self slk_commonInit];
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)coder
+{
+    if (self = [super initWithCoder:coder]) {
+        [self slk_commonInit];
+    }
+    return self;
+}
+
+- (void)slk_commonInit
+{
+    _pastableMediaTypes = SLKPastableMediaTypeNone;
+    _dynamicTypeEnabled = YES;
+
+    self.undoManagerEnabled = YES;
+    self.autoCompleteFormatting = YES;
+    
+    self.editable = YES;
+    self.selectable = YES;
+    self.scrollEnabled = YES;
+    self.scrollsToTop = NO;
+    self.directionalLockEnabled = YES;
+    self.dataDetectorTypes = UIDataDetectorTypeNone;
+    
+    [self slk_registerNotifications];
+    
+    [self addObserver:self 
forKeyPath:NSStringFromSelector(@selector(contentSize)) 
options:NSKeyValueObservingOptionNew context:NULL];
+}
+
+
+#pragma mark - UIView Overrides
+
+- (CGSize)intrinsicContentSize
+{
+    CGFloat height = self.font.lineHeight;
+    height += self.textContainerInset.top + self.textContainerInset.bottom;
+    
+    return CGSizeMake(UIViewNoIntrinsicMetric, height);
+}
+
++ (BOOL)requiresConstraintBasedLayout
+{
+    return YES;
+}
+
+- (void)layoutIfNeeded
+{
+    if (!self.window) {
+        return;
+    }
+    
+    [super layoutIfNeeded];
+}
+
+- (void)layoutSubviews
+{
+    [super layoutSubviews];
+    
+    self.placeholderLabel.hidden = [self slk_shouldHidePlaceholder];
+    
+    if (!self.placeholderLabel.hidden) {
+        
+        [UIView performWithoutAnimation:^{
+            self.placeholderLabel.frame = [self 
slk_placeholderRectThatFits:self.bounds];
+            [self sendSubviewToBack:self.placeholderLabel];
+        }];
+    }
+}
+
+
+#pragma mark - Getters
+
+- (UILabel *)placeholderLabel
+{
+    if (!_placeholderLabel) {
+        _placeholderLabel = [UILabel new];
+        _placeholderLabel.clipsToBounds = NO;
+        _placeholderLabel.autoresizesSubviews = NO;
+        _placeholderLabel.numberOfLines = 1;
+        _placeholderLabel.font = self.font;
+        _placeholderLabel.backgroundColor = [UIColor clearColor];
+        _placeholderLabel.textColor = [UIColor lightGrayColor];
+        _placeholderLabel.hidden = YES;
+        
+        [self addSubview:_placeholderLabel];
+    }
+    return _placeholderLabel;
+}
+
+- (NSString *)placeholder
+{
+    return self.placeholderLabel.text;
+}
+
+- (UIColor *)placeholderColor
+{
+    return self.placeholderLabel.textColor;
+}
+
+- (NSUInteger)numberOfLines
+{
+    CGSize contentSize = self.contentSize;
+    
+    CGFloat contentHeight = contentSize.height;
+    contentHeight -= self.textContainerInset.top + 
self.textContainerInset.bottom;
+    
+    NSUInteger lines = fabs(contentHeight/self.font.lineHeight);
+    
+    // This helps preventing the content's height to be larger that the 
bounds' height
+    // Avoiding this way to have unnecessary scrolling in the text view when 
there is only 1 line of content
+    if (lines == 1 && contentSize.height > self.bounds.size.height) {
+        contentSize.height = self.bounds.size.height;
+        self.contentSize = contentSize;
+    }
+    
+    // Let's fallback to the minimum line count
+    if (lines == 0) {
+        lines = 1;
+    }
+    
+    return lines;
+}
+
+- (NSUInteger)maxNumberOfLines
+{
+    NSUInteger numberOfLines = _maxNumberOfLines;
+    
+    if (SLK_IS_LANDSCAPE) {
+        if ((SLK_IS_IPHONE4 || SLK_IS_IPHONE5)) {
+            numberOfLines = 2.0; // 2 lines max on smaller iPhones
+        }
+        else if (SLK_IS_IPHONE) {
+            numberOfLines /= 2.0; // Half size on larger iPhone
+        }
+    }
+    
+    if (self.isDynamicTypeEnabled) {
+        NSString *contentSizeCategory = [[UIApplication sharedApplication] 
preferredContentSizeCategory];
+        CGFloat pointSizeDifference = [SLKTextView 
pointSizeDifferenceForCategory:contentSizeCategory];
+        
+        CGFloat factor = pointSizeDifference/self.initialFontSize;
+        
+        if (fabs(factor) > 0.75) {
+            factor = 0.75;
+        }
+        
+        numberOfLines -= floorf(numberOfLines * factor); // Calculates a 
dynamic number of lines depending of the user preferred font size
+    }
+    
+    return numberOfLines;
+}
+
+- (BOOL)isTypingSuggestionEnabled
+{
+    return (self.autocorrectionType == UITextAutocorrectionTypeNo) ? NO : YES;
+}
+
+- (BOOL)autoCompleteFormatting
+{
+    if (_registeredFormattingSymbols.count == 0) {
+        return NO;
+    }
+    return _autoCompleteFormatting;
+}
+
+// Returns only a supported pasted item
+- (id)slk_pastedItem
+{
+    NSString *contentType = [self slk_pasteboardContentType];
+    NSData *data = [[UIPasteboard generalPasteboard] 
dataForPasteboardType:contentType];
+    
+    if (data && [data isKindOfClass:[NSData class]])
+    {
+        SLKPastableMediaType mediaType = 
SLKPastableMediaTypeFromNSString(contentType);
+        
+        NSDictionary *userInfo = @{SLKTextViewPastedItemContentType: 
contentType,
+                                   SLKTextViewPastedItemMediaType: 
@(mediaType),
+                                   SLKTextViewPastedItemData: data};
+        return userInfo;
+    }
+    if ([[UIPasteboard generalPasteboard] URL]) {
+        return [[[UIPasteboard generalPasteboard] URL] absoluteString];
+    }
+    if ([[UIPasteboard generalPasteboard] string]) {
+        return [[UIPasteboard generalPasteboard] string];
+    }
+    
+    return nil;
+}
+
+// Checks if any supported media found in the general pasteboard
+- (BOOL)slk_isPasteboardItemSupported
+{
+    if ([self slk_pasteboardContentType].length > 0) {
+        return YES;
+    }
+    return NO;
+}
+
+- (NSString *)slk_pasteboardContentType
+{
+    NSArray *pasteboardTypes = [[UIPasteboard generalPasteboard] 
pasteboardTypes];
+    NSMutableArray *subpredicates = [NSMutableArray new];
+    
+    for (NSString *type in [self slk_supportedMediaTypes]) {
+        [subpredicates addObject:[NSPredicate predicateWithFormat:@"SELF == 
%@", type]];
+    }
+    
+    return [[pasteboardTypes filteredArrayUsingPredicate:[NSCompoundPredicate 
orPredicateWithSubpredicates:subpredicates]] firstObject];
+}
+
+- (NSArray *)slk_supportedMediaTypes
+{
+    if (self.pastableMediaTypes == SLKPastableMediaTypeNone) {
+        return nil;
+    }
+    
+    NSMutableArray *types = [NSMutableArray new];
+    
+    if (self.pastableMediaTypes & SLKPastableMediaTypePNG) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePNG)];
+    }
+    if (self.pastableMediaTypes & SLKPastableMediaTypeJPEG) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeJPEG)];
+    }
+    if (self.pastableMediaTypes & SLKPastableMediaTypeTIFF) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeTIFF)];
+    }
+    if (self.pastableMediaTypes & SLKPastableMediaTypeGIF) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeGIF)];
+    }
+    if (self.pastableMediaTypes & SLKPastableMediaTypeMOV) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeMOV)];
+    }
+    if (self.pastableMediaTypes & SLKPastableMediaTypePassbook) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePassbook)];
+    }
+    
+    if (self.pastableMediaTypes & SLKPastableMediaTypeImages) {
+        [types 
addObject:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeImages)];
+    }
+    
+    return types;
+}
+
+NSString *NSStringFromSLKPastableMediaType(SLKPastableMediaType type)
+{
+    if (type == SLKPastableMediaTypePNG) {
+        return @"public.png";
+    }
+    if (type == SLKPastableMediaTypeJPEG) {
+        return @"public.jpeg";
+    }
+    if (type == SLKPastableMediaTypeTIFF) {
+        return @"public.tiff";
+    }
+    if (type == SLKPastableMediaTypeGIF) {
+        return @"com.compuserve.gif";
+    }
+    if (type == SLKPastableMediaTypeMOV) {
+        return @"com.apple.quicktime";
+    }
+    if (type == SLKPastableMediaTypePassbook) {
+        return @"com.apple.pkpass";
+    }
+    if (type == SLKPastableMediaTypeImages) {
+        return @"com.apple.uikit.image";
+    }
+    
+    return nil;
+}
+
+SLKPastableMediaType SLKPastableMediaTypeFromNSString(NSString *string)
+{
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePNG)]) {
+        return SLKPastableMediaTypePNG;
+    }
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeJPEG)]) {
+        return SLKPastableMediaTypeJPEG;
+    }
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeTIFF)]) {
+        return SLKPastableMediaTypeTIFF;
+    }
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeGIF)]) {
+        return SLKPastableMediaTypeGIF;
+    }
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeMOV)]) {
+        return SLKPastableMediaTypeMOV;
+    }
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypePassbook)])
 {
+        return SLKPastableMediaTypePassbook;
+    }
+    if ([string 
isEqualToString:NSStringFromSLKPastableMediaType(SLKPastableMediaTypeImages)]) {
+        return SLKPastableMediaTypeImages;
+    }
+    return SLKPastableMediaTypeNone;
+}
+
+- (BOOL)isExpanding
+{
+    if (self.numberOfLines >= self.maxNumberOfLines) {
+        return YES;
+    }
+    return NO;
+}
+
+- (BOOL)slk_shouldHidePlaceholder
+{
+    if (self.placeholder.length == 0 || self.text.length > 0) {
+        return YES;
+    }
+    return NO;
+}
+
+- (CGRect)slk_placeholderRectThatFits:(CGRect)bounds
+{
+    CGFloat padding = self.textContainer.lineFragmentPadding;
+    
+    CGRect rect = CGRectZero;
+    rect.size.height = [self.placeholderLabel sizeThatFits:bounds.size].height;
+    rect.size.width = self.textContainer.size.width - padding*2.0;
+    rect.origin = UIEdgeInsetsInsetRect(bounds, 
self.textContainerInset).origin;
+    rect.origin.x += padding;
+    
+    return rect;
+}
+
+
+#pragma mark - Setters
+
+- (void)setPlaceholder:(NSString *)placeholder
+{
+    self.placeholderLabel.text = placeholder;
+    self.accessibilityLabel = placeholder;
+    
+    [self setNeedsLayout];
+}
+
+- (void)setPlaceholderColor:(UIColor *)color
+{
+    self.placeholderLabel.textColor = color;
+}
+
+- (void)setUndoManagerEnabled:(BOOL)enabled
+{
+    if (self.undoManagerEnabled == enabled) {
+        return;
+    }
+    
+    self.undoManager.levelsOfUndo = 10;
+    [self.undoManager removeAllActions];
+    [self.undoManager setActionIsDiscardable:YES];
+    
+    _undoManagerEnabled = enabled;
+}
+
+- (void)setTypingSuggestionEnabled:(BOOL)enabled
+{
+    if (self.isTypingSuggestionEnabled == enabled) {
+        return;
+    }
+    
+    self.autocorrectionType = enabled ? UITextAutocorrectionTypeDefault : 
UITextAutocorrectionTypeNo;
+    self.spellCheckingType = enabled ? UITextSpellCheckingTypeDefault : 
UITextSpellCheckingTypeNo;
+    
+    [self refreshFirstResponder];
+}
+
+
+#pragma mark - UITextView Overrides
+
+- (void)setSelectedRange:(NSRange)selectedRange
+{
+    [super setSelectedRange:selectedRange];
+}
+
+- (void)setSelectedTextRange:(UITextRange *)selectedTextRange
+{
+    [super setSelectedTextRange:selectedTextRange];
+    
+    [[NSNotificationCenter defaultCenter] 
postNotificationName:SLKTextViewSelectedRangeDidChangeNotification object:self 
userInfo:nil];
+}
+
+- (void)setText:(NSString *)text
+{
+    // Registers for undo management
+    [self slk_prepareForUndo:@"Text Set"];
+    
+    [super setText:text];
+    
+    [[NSNotificationCenter defaultCenter] 
postNotificationName:UITextViewTextDidChangeNotification object:self];
+}
+
+- (void)setAttributedText:(NSAttributedString *)attributedText
+{
+    // Registers for undo management
+    [self slk_prepareForUndo:@"Attributed Text Set"];
+    
+    [super setAttributedText:attributedText];
+    
+    [[NSNotificationCenter defaultCenter] 
postNotificationName:UITextViewTextDidChangeNotification object:self];
+}
+
+- (void)setFont:(UIFont *)font
+{
+    NSString *contentSizeCategory = [[UIApplication sharedApplication] 
preferredContentSizeCategory];
+    
+    [self setFontName:font.fontName pointSize:font.pointSize 
withContentSizeCategory:contentSizeCategory];
+    
+    self.initialFontSize = font.pointSize;
+}
+
+- (void)setFontName:(NSString *)fontName pointSize:(CGFloat)pointSize 
withContentSizeCategory:(NSString *)contentSizeCategory
+{
+    if (self.isDynamicTypeEnabled) {
+        pointSize += [SLKTextView 
pointSizeDifferenceForCategory:contentSizeCategory];
+    }
+    
+    UIFont *dynamicFont = [UIFont fontWithName:fontName size:pointSize];
+    
+    [super setFont:dynamicFont];
+    
+    // Updates the placeholder font too
+    self.placeholderLabel.font = dynamicFont;
+}
+
+- (void)setDynamicTypeEnabled:(BOOL)dynamicTypeEnabled
+{
+    if (self.isDynamicTypeEnabled == dynamicTypeEnabled) {
+        return;
+    }
+    
+    _dynamicTypeEnabled = dynamicTypeEnabled;
+    
+    NSString *contentSizeCategory = [[UIApplication sharedApplication] 
preferredContentSizeCategory];
+
+    [self setFontName:self.font.fontName pointSize:self.initialFontSize 
withContentSizeCategory:contentSizeCategory];
+}
+
+- (void)setTextAlignment:(NSTextAlignment)textAlignment
+{
+    [super setTextAlignment:textAlignment];
+    
+    // Updates the placeholder text alignment too
+    self.placeholderLabel.textAlignment = textAlignment;
+}
+
+
+#pragma mark - UITextInput Overrides
+
+- (void)beginFloatingCursorAtPoint:(CGPoint)point
+{
+    [super beginFloatingCursorAtPoint:point];
+    
+    _trackpadEnabled = YES;
+}
+
+- (void)updateFloatingCursorAtPoint:(CGPoint)point
+{
+    [super updateFloatingCursorAtPoint:point];
+}
+
+- (void)endFloatingCursor
+{
+    [super endFloatingCursor];
+
+    _trackpadEnabled = NO;
+    
+    // We still need to notify a selection change in the textview after the 
trackpad is disabled
+    if (self.delegate && [self.delegate 
respondsToSelector:@selector(textViewDidChangeSelection:)]) {
+        [self.delegate textViewDidChangeSelection:self];
+    }
+    
+    [[NSNotificationCenter defaultCenter] 
postNotificationName:SLKTextViewSelectedRangeDidChangeNotification object:self 
userInfo:nil];
+}
+
+
+#pragma mark - UIResponder Overrides
+
+- (BOOL)canBecomeFirstResponder
+{
+    [self slk_addCustomMenuControllerItems];
+    
+    return [super canBecomeFirstResponder];
+}
+
+- (BOOL)becomeFirstResponder
+{
+    return [super becomeFirstResponder];
+}
+
+- (BOOL)canResignFirstResponder
+{
+    // Removes undo/redo items
+    if (self.undoManagerEnabled) {
+        [self.undoManager removeAllActions];
+    }
+    
+    return [super canResignFirstResponder];
+}
+
+- (BOOL)resignFirstResponder
+{
+    return [super resignFirstResponder];
+}
+
+- (BOOL)canPerformAction:(SEL)action withSender:(id)sender
+{
+    if (self.isFormatting) {
+        NSString *title = [self slk_formattingTitleFromSelector:action];
+        NSString *symbol = [self slk_formattingSymbolWithTitle:title];
+        
+        if (symbol.length > 0) {
+            if (self.delegate && [self.delegate 
respondsToSelector:@selector(textView:shouldOfferFormattingForSymbol:)]) {
+                return [self.delegate textView:self 
shouldOfferFormattingForSymbol:symbol];
+            }
+            else {
+                return YES;
+            }
+        }
+        
+        return NO;
+    }
+
+    if (action == @selector(delete:)) {
+        return NO;
+    }
+    
+    if (action == NSSelectorFromString(@"_share:") || action == 
NSSelectorFromString(@"_define:") || action == 
NSSelectorFromString(@"_promptForReplace:")) {
+        return NO;
+    }
+    
+    if (action == @selector(slk_presentFormattingMenu:)) {
+        return self.selectedRange.length > 0 ? YES : NO;
+    }
+    
+    if (action == @selector(paste:) && [self slk_isPasteboardItemSupported]) {
+        return YES;
+    }
+    
+    if (action == @selector(paste:) && [self slk_isPasteboardItemSupported]) {
+        return YES;
+    }
+    
+    if (self.undoManagerEnabled) {
+        if (action == @selector(slk_undo:)) {
+            if (self.undoManager.undoActionIsDiscardable) {
+                return NO;
+            }
+            return [self.undoManager canUndo];
+        }
+        if (action == @selector(slk_redo:)) {
+            if (self.undoManager.redoActionIsDiscardable) {
+                return NO;
+            }
+            return [self.undoManager canRedo];
+        }
+    }
+    
+    return [super canPerformAction:action withSender:sender];
+}
+
+- (void)paste:(id)sender
+{
+    id pastedItem = [self slk_pastedItem];
+    
+    if ([pastedItem isKindOfClass:[NSDictionary class]]) {
+        [[NSNotificationCenter defaultCenter] 
postNotificationName:SLKTextViewDidPasteItemNotification object:nil 
userInfo:pastedItem];
+    }
+    else if ([pastedItem isKindOfClass:[NSString class]]) {
+        // Respect the delegate yo!
+        if (self.delegate && [self.delegate 
respondsToSelector:@selector(textView:shouldChangeTextInRange:replacementText:)])
 {
+            if (![self.delegate textView:self 
shouldChangeTextInRange:self.selectedRange replacementText:pastedItem]) {
+                return;
+            }
+        }
+        
+        // Inserting the text fixes a UITextView bug whitch automatically 
scrolls to the bottom
+        // and beyond scroll content size sometimes when the text is too long
+        [self slk_insertTextAtCaretRange:pastedItem];
+    }
+}
+
+
+#pragma mark - NSObject Overrides
+
+- (NSMethodSignature *)methodSignatureForSelector:(SEL)sel
+{
+    if ([super methodSignatureForSelector:sel]) {
+        return [super methodSignatureForSelector:sel];
+    }
+    return [super methodSignatureForSelector:@selector(slk_format:)];
+}
+
+- (void)forwardInvocation:(NSInvocation *)invocation
+{
+    NSString *title = [self slk_formattingTitleFromSelector:[invocation 
selector]];
+    
+    if (title.length > 0) {
+        [self slk_format:title];
+    }
+    else {
+        [super forwardInvocation:invocation];
+    }
+}
+
+
+#pragma mark - Custom Actions
+
+- (void)slk_flashScrollIndicatorsIfNeeded
+{
+    if (self.numberOfLines == self.maxNumberOfLines+1) {
+        if (!_didFlashScrollIndicators) {
+            _didFlashScrollIndicators = YES;
+            [super flashScrollIndicators];
+        }
+    }
+    else if (_didFlashScrollIndicators) {
+        _didFlashScrollIndicators = NO;
+    }
+}
+
+- (void)refreshFirstResponder
+{
+    if (!self.isFirstResponder) {
+        return;
+    }
+    
+    _didNotResignFirstResponder = YES;
+    [self resignFirstResponder];
+    
+    _didNotResignFirstResponder = NO;
+    [self becomeFirstResponder];
+}
+
+- (void)refreshInputViews
+{
+    _didNotResignFirstResponder = YES;
+    
+    [super reloadInputViews];
+    
+    _didNotResignFirstResponder = NO;
+}
+
+- (void)slk_addCustomMenuControllerItems
+{
+    UIMenuItem *undo = [[UIMenuItem alloc] 
initWithTitle:NSLocalizedString(@"Undo", nil) action:@selector(slk_undo:)];
+    UIMenuItem *redo = [[UIMenuItem alloc] 
initWithTitle:NSLocalizedString(@"Redo", nil) action:@selector(slk_redo:)];
+    UIMenuItem *format = [[UIMenuItem alloc] 
initWithTitle:NSLocalizedString(@"Format", nil) 
action:@selector(slk_presentFormattingMenu:)];
+    
+    [[UIMenuController sharedMenuController] setMenuItems:@[undo, redo, 
format]];
+}
+
+- (void)slk_undo:(id)sender
+{
+    [self.undoManager undo];
+}
+
+- (void)slk_redo:(id)sender
+{
+    [self.undoManager redo];
+}
+
+- (void)slk_presentFormattingMenu:(id)sender
+{
+    NSMutableArray *items = [NSMutableArray 
arrayWithCapacity:self.registeredFormattingTitles.count];
+    
+    for (NSString *name in self.registeredFormattingTitles) {
+        
+        NSString *sel = [NSString stringWithFormat:@"%@%@", 
SLKTextViewGenericFormattingSelectorPrefix, name];
+        
+        UIMenuItem *item = [[UIMenuItem alloc] initWithTitle:name 
action:NSSelectorFromString(sel)];
+        [items addObject:item];
+    }
+    
+    self.formatting = YES;
+    
+    UIMenuController *menu = [UIMenuController sharedMenuController];
+    [menu setMenuItems:items];
+    
+    NSLayoutManager *manager = self.layoutManager;
+    CGRect targetRect = [manager boundingRectForGlyphRange:self.selectedRange 
inTextContainer:self.textContainer];
+    
+    [menu setTargetRect:targetRect inView:self];
+    
+    [menu setMenuVisible:YES animated:YES];
+}
+
+- (NSString *)slk_formattingTitleFromSelector:(SEL)selector
+{
+    NSString *selectorString = NSStringFromSelector(selector);
+    NSRange match = [selectorString 
rangeOfString:SLKTextViewGenericFormattingSelectorPrefix];
+    
+    if (match.location != NSNotFound) {
+        return [selectorString 
substringFromIndex:SLKTextViewGenericFormattingSelectorPrefix.length];
+    }
+    
+    return nil;
+}
+
+- (NSString *)slk_formattingSymbolWithTitle:(NSString *)title
+{
+    NSUInteger idx = [self.registeredFormattingTitles indexOfObject:title];
+    
+    if (idx <= self.registeredFormattingSymbols.count -1) {
+        return self.registeredFormattingSymbols[idx];
+    }
+    
+    return nil;
+}
+
+- (void)slk_format:(NSString *)titles
+{
+    NSString *symbol = [self slk_formattingSymbolWithTitle:titles];
+    
+    if (symbol.length > 0) {
+        NSRange selection = self.selectedRange;
+        
+        NSRange range = [self slk_insertText:symbol 
inRange:NSMakeRange(selection.location, 0)];
+        range.location += selection.length;
+        range.length = 0;
+        
+        // The default behavior is to add a closure
+        BOOL addClosure = YES;
+        
+        if (self.delegate && [self.delegate 
respondsToSelector:@selector(textView:shouldInsertSuffixForFormattingWithSymbol:prefixRange:)])
 {
+            addClosure = [self.delegate textView:self 
shouldInsertSuffixForFormattingWithSymbol:symbol prefixRange:selection];
+        }
+        
+        if (addClosure) {
+            self.selectedRange = [self slk_insertText:symbol inRange:range];
+        }
+    }
+}
+
+
+#pragma mark - Markdown Formatting
+
+- (void)registerMarkdownFormattingSymbol:(NSString *)symbol 
withTitle:(NSString *)title
+{
+    if (!symbol || !title) {
+        return;
+    }
+    
+    if (!_registeredFormattingTitles) {
+        _registeredFormattingTitles = [NSMutableArray new];
+        _registeredFormattingSymbols = [NSMutableArray new];
+    }
+    
+    // Adds the symbol if not contained already
+    if (![self.registeredSymbols containsObject:symbol]) {
+        [self.registeredFormattingTitles addObject:title];
+        [self.registeredFormattingSymbols addObject:symbol];
+    }
+}
+
+- (NSArray *)registeredSymbols
+{
+    return self.registeredFormattingSymbols;
+}
+
+
+#pragma mark - Notification Events
+
+- (void)slk_didBeginEditing:(NSNotification *)notification
+{
+    if (![notification.object isEqual:self]) {
+        return;
+    }
+    
+    // Do something
+}
+
+- (void)slk_didChangeText:(NSNotification *)notification
+{
+    if (![notification.object isEqual:self]) {
+        return;
+    }
+    
+    if (self.placeholderLabel.hidden != [self slk_shouldHidePlaceholder]) {
+        [self setNeedsLayout];
+    }
+    
+    [self slk_flashScrollIndicatorsIfNeeded];
+}
+
+- (void)slk_didEndEditing:(NSNotification *)notification
+{
+    if (![notification.object isEqual:self]) {
+        return;
+    }
+    
+    // Do something
+}
+
+- (void)slk_didChangeTextInputMode:(NSNotification *)notification
+{
+    // Do something
+}
+
+- (void)slk_didChangeContentSizeCategory:(NSNotification *)notification
+{
+    if (!self.isDynamicTypeEnabled) {
+        return;
+    }
+    
+    NSString *contentSizeCategory = 
notification.userInfo[UIContentSizeCategoryNewValueKey];
+    
+    [self setFontName:self.font.fontName pointSize:self.initialFontSize 
withContentSizeCategory:contentSizeCategory];
+    
+    NSString *text = [self.text copy];
+    
+    // Reloads the content size of the text view
+    [self setText:@" "];
+    [self setText:text];
+}
+
+- (void)slk_willShowMenuController:(NSNotification *)notification
+{
+    
+}
+
+- (void)slk_didHideMenuController:(NSNotification *)notification
+{
+    self.formatting = NO;
+    
+    [self slk_addCustomMenuControllerItems];
+}
+
+
+#pragma mark - KVO Listener
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object 
change:(NSDictionary *)change context:(void *)context
+{
+    if ([object isEqual:self] && [keyPath 
isEqualToString:NSStringFromSelector(@selector(contentSize))]) {
+        [[NSNotificationCenter defaultCenter] 
postNotificationName:SLKTextViewContentSizeDidChangeNotification object:self 
userInfo:nil];
+    }
+    else {
+        [super observeValueForKeyPath:keyPath ofObject:object change:change 
context:context];
+    }
+}
+
+
+#pragma mark - Motion Events
+
+- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event
+{
+    if (event.type == UIEventTypeMotion && event.subtype == 
UIEventSubtypeMotionShake) {
+        [[NSNotificationCenter defaultCenter] 
postNotificationName:SLKTextViewDidShakeNotification object:self];
+    }
+}
+
+
+#pragma mark - External Keyboard Support
+
+- (NSArray *)keyCommands
+{
+    if (_keyboardCommands) {
+        return _keyboardCommands;
+    }
+    
+    _keyboardCommands = @[
+         // Return
+         [UIKeyCommand keyCommandWithInput:@"\r" 
modifierFlags:UIKeyModifierShift action:@selector(slk_didPressLineBreakKeys:)],
+         [UIKeyCommand keyCommandWithInput:@"\r" 
modifierFlags:UIKeyModifierAlternate 
action:@selector(slk_didPressLineBreakKeys:)],
+         [UIKeyCommand keyCommandWithInput:@"\r" 
modifierFlags:UIKeyModifierControl 
action:@selector(slk_didPressLineBreakKeys:)],
+         
+         // Undo/Redo
+         [UIKeyCommand keyCommandWithInput:@"z" 
modifierFlags:UIKeyModifierCommand action:@selector(slk_didPressCommandZKeys:)],
+         [UIKeyCommand keyCommandWithInput:@"z" 
modifierFlags:UIKeyModifierShift|UIKeyModifierCommand 
action:@selector(slk_didPressCommandZKeys:)],
+         ];
+    
+    return _keyboardCommands;
+}
+
+
+#pragma mark Line Break
+
+- (void)slk_didPressLineBreakKeys:(id)sender
+{
+    [self slk_insertNewLineBreak];
+}
+
+
+#pragma mark Undo/Redo Text
+
+- (void)slk_didPressCommandZKeys:(id)sender
+{
+    if (!self.undoManagerEnabled) {
+        return;
+    }
+    
+    UIKeyCommand *keyCommand = (UIKeyCommand *)sender;
+    
+    if ((keyCommand.modifierFlags & UIKeyModifierShift) > 0) {
+        
+        if ([self.undoManager canRedo]) {
+            [self.undoManager redo];
+        }
+    }
+    else {
+        if ([self.undoManager canUndo]) {
+            [self.undoManager undo];
+        }
+    }
+}
+
+#pragma mark Up/Down Cursor Movement
+
+- (void)didPressAnyArrowKey:(id)sender
+{
+    if (self.text.length == 0 || self.numberOfLines < 2) {
+        return;
+    }
+    
+    UIKeyCommand *keyCommand = (UIKeyCommand *)sender;
+    
+    if ([keyCommand.input isEqualToString:UIKeyInputUpArrow]) {
+        [self slk_moveCursorTodirection:UITextLayoutDirectionUp];
+    }
+    else if ([keyCommand.input isEqualToString:UIKeyInputDownArrow]) {
+        [self slk_moveCursorTodirection:UITextLayoutDirectionDown];
+    }
+}
+
+- (void)slk_moveCursorTodirection:(UITextLayoutDirection)direction
+{
+    UITextPosition *start = (direction == UITextLayoutDirectionUp) ? 
self.selectedTextRange.start : self.selectedTextRange.end;
+    
+    if ([self slk_isNewVerticalMovementForPosition:start 
inDirection:direction]) {
+        self.verticalMoveDirection = direction;
+        self.verticalMoveStartCaretRect = [self caretRectForPosition:start];
+    }
+    
+    if (start) {
+        UITextPosition *end = [self slk_closestPositionToPosition:start 
inDirection:direction];
+        
+        if (end) {
+            self.verticalMoveLastCaretRect = [self caretRectForPosition:end];
+            self.selectedTextRange = [self textRangeFromPosition:end 
toPosition:end];
+            
+            [self slk_scrollToCaretPositonAnimated:NO];
+        }
+    }
+}
+
+// Based on code from Ruben Cabaco
+// https://gist.github.com/rcabaco/6765778
+
+- (UITextPosition *)slk_closestPositionToPosition:(UITextPosition *)position 
inDirection:(UITextLayoutDirection)direction
+{
+    // Only up/down are implemented. No real need for left/right since that is 
native to UITextInput.
+    NSParameterAssert(direction == UITextLayoutDirectionUp || direction == 
UITextLayoutDirectionDown);
+    
+    // Translate the vertical direction to a horizontal direction.
+    UITextLayoutDirection lookupDirection = (direction == 
UITextLayoutDirectionUp) ? UITextLayoutDirectionLeft : 
UITextLayoutDirectionRight;
+    
+    // Walk one character at a time in `lookupDirection` until the next line 
is reached.
+    UITextPosition *checkPosition = position;
+    UITextPosition *closestPosition = position;
+    CGRect startingCaretRect = [self caretRectForPosition:position];
+    CGRect nextLineCaretRect;
+    BOOL isInNextLine = NO;
+    
+    while (YES) {
+        UITextPosition *nextPosition = [self 
positionFromPosition:checkPosition inDirection:lookupDirection offset:1];
+        
+        // End of line.
+        if (!nextPosition || [self comparePosition:checkPosition 
toPosition:nextPosition] == NSOrderedSame) {
+            break;
+        }
+        
+        checkPosition = nextPosition;
+        CGRect checkRect = [self caretRectForPosition:checkPosition];
+        if (CGRectGetMidY(startingCaretRect) != CGRectGetMidY(checkRect)) {
+            // While on the next line stop just above/below the starting 
position.
+            if (lookupDirection == UITextLayoutDirectionLeft && 
CGRectGetMidX(checkRect) <= CGRectGetMidX(self.verticalMoveStartCaretRect)) {
+                closestPosition = checkPosition;
+                break;
+            }
+            if (lookupDirection == UITextLayoutDirectionRight && 
CGRectGetMidX(checkRect) >= CGRectGetMidX(self.verticalMoveStartCaretRect)) {
+                closestPosition = checkPosition;
+                break;
+            }
+            // But don't skip lines.
+            if (isInNextLine && CGRectGetMidY(checkRect) != 
CGRectGetMidY(nextLineCaretRect)) {
+                break;
+            }
+            
+            isInNextLine = YES;
+            nextLineCaretRect = checkRect;
+            closestPosition = checkPosition;
+        }
+    }
+    return closestPosition;
+}
+
+- (BOOL)slk_isNewVerticalMovementForPosition:(UITextPosition *)position 
inDirection:(UITextLayoutDirection)direction
+{
+    CGRect caretRect = [self caretRectForPosition:position];
+    BOOL noPreviousStartPosition = 
CGRectEqualToRect(self.verticalMoveStartCaretRect, CGRectZero);
+    BOOL caretMovedSinceLastPosition = !CGRectEqualToRect(caretRect, 
self.verticalMoveLastCaretRect);
+    BOOL directionChanged = self.verticalMoveDirection != direction;
+    
+    BOOL newMovement = noPreviousStartPosition || caretMovedSinceLastPosition 
|| directionChanged;
+    return newMovement;
+}
+
+
+#pragma mark - NSNotificationCenter register/unregister
+
+- (void)slk_registerNotifications
+{
+    [self slk_unregisterNotifications];
+    
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_didBeginEditing:) 
name:UITextViewTextDidBeginEditingNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_didChangeText:) name:UITextViewTextDidChangeNotification 
object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_didEndEditing:) 
name:UITextViewTextDidEndEditingNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_didChangeTextInputMode:) 
name:UITextInputCurrentInputModeDidChangeNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_didChangeContentSizeCategory:) 
name:UIContentSizeCategoryDidChangeNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_willShowMenuController:) 
name:UIMenuControllerWillShowMenuNotification object:nil];
+    [[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(slk_didHideMenuController:) 
name:UIMenuControllerDidHideMenuNotification object:nil];
+}
+
+- (void)slk_unregisterNotifications
+{
+    [[NSNotificationCenter defaultCenter] removeObserver:self 
name:UITextViewTextDidBeginEditingNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self 
name:UITextViewTextDidChangeNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self 
name:UITextViewTextDidEndEditingNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self 
name:UITextInputCurrentInputModeDidChangeNotification object:nil];
+    [[NSNotificationCenter defaultCenter] removeObserver:self 
name:UIContentSizeCategoryDidChangeNotification object:nil];
+}
+
+
+#pragma mark - Lifeterm
+
+- (void)dealloc
+{
+    [self slk_unregisterNotifications];
+    
+    [self removeObserver:self 
forKeyPath:NSStringFromSelector(@selector(contentSize))];
+    
+    _placeholderLabel = nil;
+}
+
+@end

http://git-wip-us.apache.org/repos/asf/usergrid/blob/7442c881/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.h
----------------------------------------------------------------------
diff --git 
a/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.h
 
b/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.h
new file mode 100644
index 0000000..1e429d3
--- /dev/null
+++ 
b/sdks/swift/Samples/ActivityFeed/Pods/SlackTextViewController/Source/SLKTextViewController.h
@@ -0,0 +1,584 @@
+//
+//   Copyright 2014 Slack Technologies, Inc.
+//
+//   Licensed under the Apache License, Version 2.0 (the "License");
+//   you may not use this file except in compliance with the License.
+//   You may obtain a copy of the License at
+//
+//       http://www.apache.org/licenses/LICENSE-2.0
+//
+//   Unless required by applicable law or agreed to in writing, software
+//   distributed under the License is distributed on an "AS IS" BASIS,
+//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//   See the License for the specific language governing permissions and
+//   limitations under the License.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "SLKTextInputbar.h"
+#import "SLKTextView.h"
+#import "SLKTypingIndicatorView.h"
+#import "SLKTypingIndicatorProtocol.h"
+
+#import "SLKTextView+SLKAdditions.h"
+#import "UIScrollView+SLKAdditions.h"
+#import "UIView+SLKAdditions.h"
+
+#import "SLKUIConstants.h"
+
+/**
+ UIKeyboard notification replacement, posting reliably only when 
showing/hiding the keyboard (not when resizing keyboard, or with 
inputAccessoryView reloads, etc).
+ Only triggered when using SLKTextViewController's text view.
+ */
+UIKIT_EXTERN NSString *const SLKKeyboardWillShowNotification;
+UIKIT_EXTERN NSString *const SLKKeyboardDidShowNotification;
+UIKIT_EXTERN NSString *const SLKKeyboardWillHideNotification;
+UIKIT_EXTERN NSString *const SLKKeyboardDidHideNotification;
+
+/**
+ This feature doesn't work on iOS 9 due to no legit alternatives to detect the 
keyboard view.
+ Open Radar: http://openradar.appspot.com/radar?id=5021485877952512
+ */
+UIKIT_EXTERN NSString *const SLKTextInputbarDidMoveNotification;
+
+typedef NS_ENUM(NSUInteger, SLKKeyboardStatus) {
+    SLKKeyboardStatusDidHide,
+    SLKKeyboardStatusWillShow,
+    SLKKeyboardStatusDidShow,
+    SLKKeyboardStatusWillHide
+};
+
+/** @name A drop-in UIViewController subclass with a growing text input view 
and other useful messaging features. */
+NS_CLASS_AVAILABLE_IOS(7_0) @interface SLKTextViewController : 
UIViewController <SLKTextViewDelegate, UITableViewDelegate, 
UITableViewDataSource,
+                                                                               
 UICollectionViewDelegate, UICollectionViewDataSource,
+                                                                               
 UIGestureRecognizerDelegate, UIAlertViewDelegate>
+
+/** The main table view managed by the controller object. Created by default 
initializing with -init or initWithNibName:bundle: */
+@property (nonatomic, readonly) UITableView *tableView;
+
+/** The main collection view managed by the controller object. Not nil if the 
controller is initialised with -initWithCollectionViewLayout: */
+@property (nonatomic, readonly) UICollectionView *collectionView;
+
+/** The main scroll view managed by the controller object. Not nil if the 
controller is initialised with -initWithScrollView: */
+@property (nonatomic, readonly) UIScrollView *scrollView;
+
+/** The bottom toolbar containing a text view and buttons. */
+@property (nonatomic, readonly) SLKTextInputbar *textInputbar;
+
+/** The default typing indicator used to display user names horizontally. */
+@property (nonatomic, readonly) SLKTypingIndicatorView *typingIndicatorView;
+
+/**
+ The custom typing indicator view. Default is kind of SLKTypingIndicatorView.
+ To customize the typing indicator view, you will need to call 
-registerClassForTypingIndicatorView: nside of any initialization method.
+ To interact with it directly, you will need to cast the return value of 
-typingIndicatorProxyView to the appropriate type.
+ */
+@property (nonatomic, readonly) UIView <SLKTypingIndicatorProtocol> 
*typingIndicatorProxyView;
+
+/** A single tap gesture used to dismiss the keyboard. SLKTextViewController 
is its delegate. */
+@property (nonatomic, readonly) UIGestureRecognizer *singleTapGesture;
+
+/** A vertical pan gesture used for bringing the keyboard from the bottom. 
SLKTextViewController is its delegate. */
+@property (nonatomic, readonly) UIPanGestureRecognizer *verticalPanGesture;
+
+/** YES if control's animation should have bouncy effects. Default is YES. */
+@property (nonatomic, assign) BOOL bounces;
+
+/** YES if text view's content can be cleaned with a shake gesture. Default is 
NO. */
+@property (nonatomic, assign) BOOL shakeToClearEnabled;
+
+/**
+ YES if keyboard can be dismissed gradually with a vertical panning gesture. 
Default is YES.
+ 
+ This feature doesn't work on iOS 9 due to no legit alternatives to detect the 
keyboard view.
+ Open Radar: http://openradar.appspot.com/radar?id=5021485877952512
+ */
+@property (nonatomic, assign, getter = isKeyboardPanningEnabled) BOOL 
keyboardPanningEnabled;
+
+/** YES if an external keyboard has been detected (this value updates only 
when the text view becomes first responder). */
+@property (nonatomic, readonly, getter=isExternalKeyboardDetected) BOOL 
externalKeyboardDetected;
+
+/** YES if the keyboard has been detected as undocked or split (iPad Only). */
+@property (nonatomic, readonly, getter=isKeyboardUndocked) BOOL 
keyboardUndocked;
+
+/** YES if after right button press, the text view is cleared out. Default is 
YES. */
+@property (nonatomic, assign) BOOL shouldClearTextAtRightButtonPress;
+
+/** YES if the scrollView should scroll to bottom when the keyboard is shown. 
Default is NO.*/
+@property (nonatomic, assign) BOOL shouldScrollToBottomAfterKeyboardShows;
+
+/**
+ YES if the main table view is inverted. Default is YES.
+ This allows the table view to start from the bottom like any typical 
messaging interface.
+ If inverted, you must assign the same transform property to your cells to 
match the orientation (ie: cell.transform = tableView.transform;)
+ Inverting the table view will enable some great features such as content 
offset corrections automatically when resizing the text input and/or showing 
autocompletion.
+ */
+@property (nonatomic, assign, getter = isInverted) BOOL inverted;
+
+/** YES if the view controller is presented inside of a popover controller. If 
YES, the keyboard won't move the text input bar and tapping on the 
tableView/collectionView will not cause the keyboard to be dismissed. This 
property is compatible only with iPad. */
+@property (nonatomic, assign, getter = isPresentedInPopover) BOOL 
presentedInPopover;
+
+/** Convenience accessors (accessed through the text input bar) */
+@property (nonatomic, readonly) SLKTextView *textView;
+@property (nonatomic, readonly) UIButton *leftButton;
+@property (nonatomic, readonly) UIButton *rightButton;
+
+
+#pragma mark - Initialization
+///------------------------------------------------
+/// @name Initialization
+///------------------------------------------------
+
+/**
+ Initializes a text view controller to manage a table view of a given style.
+ If you use the standard -init method, a table view with plain style will be 
created.
+ 
+ @param style A constant that specifies the style of main table view that the 
controller object is to manage (UITableViewStylePlain or 
UITableViewStyleGrouped).
+ @return An initialized SLKTextViewController object or nil if the object 
could not be created.
+ */
+- (instancetype)initWithTableViewStyle:(UITableViewStyle)style 
SLK_DESIGNATED_INITIALIZER;
+
+/**
+ Initializes a collection view controller and configures the collection view 
with the provided layout.
+ If you use the standard -init method, a table view with plain style will be 
created.
+ 
+ @param layout The layout object to associate with the collection view. The 
layout controls how the collection view presents its cells and supplementary 
views.
+ @return An initialized SLKTextViewController object or nil if the object 
could not be created.
+ */
+- (instancetype)initWithCollectionViewLayout:(UICollectionViewLayout *)layout 
SLK_DESIGNATED_INITIALIZER;
+
+/**
+ Initializes a text view controller to manage an arbitraty scroll view. The 
caller is responsible for configuration of the scroll view, including wiring 
the delegate.
+ 
+ @param a UISCrollView to be used as the main content area.
+ @return An initialized SLKTextViewController object or nil if the object 
could not be created.
+ */
+- (instancetype)initWithScrollView:(UIScrollView *)scrollView 
SLK_DESIGNATED_INITIALIZER;
+
+/**
+ Initializes either a table or collection view controller.
+ You must override either +tableViewStyleForCoder: or 
+collectionViewLayoutForCoder: to define witch view to be layed out.
+ 
+ @param decoder An unarchiver object.
+ @return An initialized SLKTextViewController object or nil if the object 
could not be created.
+ */
+- (instancetype)initWithCoder:(NSCoder *)decoder SLK_DESIGNATED_INITIALIZER;
+
+/**
+ Returns the tableView style to be configured when using Interface Builder. 
Default is UITableViewStylePlain.
+ You must override this method if you want to configure a tableView.
+ 
+ @param decoder An unarchiver object.
+ @return The tableView style to be used in the new instantiated tableView.
+ */
++ (UITableViewStyle)tableViewStyleForCoder:(NSCoder *)decoder;
+
+/**
+ Returns the tableView style to be configured when using Interface Builder. 
Default is nil.
+ You must override this method if you want to configure a collectionView.
+ 
+ @param decoder An unarchiver object.
+ @return The collectionView style to be used in the new instantiated 
collectionView.
+ */
++ (UICollectionViewLayout *)collectionViewLayoutForCoder:(NSCoder *)decoder;
+
+
+#pragma mark - Keyboard Handling
+///------------------------------------------------
+/// @name Keyboard Handling
+///------------------------------------------------
+
+/**
+ Presents the keyboard, if not already, animated.
+ You can override this method to perform additional tasks associated with 
presenting the keyboard.
+ You SHOULD call super to inherit some conditionals.
+
+ @param animated YES if the keyboard should show using an animation.
+ */
+- (void)presentKeyboard:(BOOL)animated;
+
+/**
+ Dimisses the keyboard, if not already, animated.
+ You can override this method to perform additional tasks associated with 
dismissing the keyboard.
+ You SHOULD call super to inherit some conditionals.
+ 
+ @param animated YES if the keyboard should be dismissed using an animation.
+ */
+- (void)dismissKeyboard:(BOOL)animated;
+
+/**
+ Verifies if the text input bar should still move up/down even if it is not 
first responder. Default is NO.
+ You can override this method to perform additional tasks associated with 
presenting the view.
+ You don't need call super since this method doesn't do anything.
+ 
+ @param responder The current first responder object.
+ @return YES so the text input bar still move up/down.
+ */
+- (BOOL)forceTextInputbarAdjustmentForResponder:(UIResponder *)responder;
+
+/**
+ Verifies if the text input bar should still move up/down when it is first 
responder. Default is NO.
+ This is very useful when presenting the view controller in a custom modal 
presentation, when there keyboard events are being handled externally to 
reframe the presented view.
+ You SHOULD call super to inherit some conditionals.
+ */
+- (BOOL)ignoreTextInputbarAdjustment NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller that the keyboard changed status.
+ You can override this method to perform additional tasks associated with 
presenting the view.
+ You don't need call super since this method doesn't do anything.
+ 
+ @param status The new keyboard status.
+ */
+- (void)didChangeKeyboardStatus:(SLKKeyboardStatus)status;
+
+
+#pragma mark - Interaction Notifications
+///------------------------------------------------
+/// @name Interaction Notifications
+///------------------------------------------------
+
+/**
+ Notifies the view controller that the text will update.
+ You can override this method to perform additional tasks associated with text 
changes.
+ You MUST call super at some point in your implementation.
+ */
+- (void)textWillUpdate NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller that the text did update.
+ You can override this method to perform additional tasks associated with text 
changes.
+ You MUST call super at some point in your implementation.
+ 
+ @param If YES, the text input bar will be resized using an animation.
+ */
+- (void)textDidUpdate:(BOOL)animated NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller that the text selection did change.
+ Use this method a replacement of UITextViewDelegate's 
-textViewDidChangeSelection: which is not reliable enough when using 
third-party keyboards (they don't forward events properly sometimes).
+ 
+ You can override this method to perform additional tasks associated with text 
changes.
+ You MUST call super at some point in your implementation.
+ */
+- (void)textSelectionDidChange NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller when the left button's action has been 
triggered, manually.
+ You can override this method to perform additional tasks associated with the 
left button.
+ You don't need call super since this method doesn't do anything.
+ 
+ @param sender The object calling this method.
+ */
+- (void)didPressLeftButton:(id)sender;
+
+/**
+ Notifies the view controller when the right button's action has been 
triggered, manually or by using the keyboard return key.
+ You can override this method to perform additional tasks associated with the 
right button.
+ You MUST call super at some point in your implementation.
+ 
+ @param sender The object calling this method.
+ */
+- (void)didPressRightButton:(id)sender NS_REQUIRES_SUPER;
+
+/**
+ Verifies if the right button can be pressed. If NO, the button is disabled.
+ You can override this method to perform additional tasks. You SHOULD call 
super to inherit some conditionals.
+ 
+ @return YES if the right button can be pressed.
+ */
+- (BOOL)canPressRightButton;
+
+/**
+ Notifies the view controller when the user has pasted a supported media 
content (images and/or videos).
+ You can override this method to perform additional tasks associated with 
image/video pasting. You don't need to call super since this method doesn't do 
anything.
+ Only supported pastable medias configured in SLKTextView will be forwarded 
(take a look at SLKPastableMediaType).
+ 
+ @para userInfo The payload containing the media data, content and media types.
+ */
+- (void)didPasteMediaContent:(NSDictionary *)userInfo;
+
+/**
+ Verifies that the typing indicator view should be shown. Default is YES, if 
meeting some requierements.
+ You can override this method to perform additional tasks.
+ You SHOULD call super to inherit some conditionals.
+ 
+ @return YES if the typing indicator view should be presented.
+ */
+- (BOOL)canShowTypingIndicator;
+
+/**
+ Notifies the view controller when the user has shaked the device for undoing 
text typing.
+ You can override this method to perform additional tasks associated with the 
shake gesture.
+ Calling super will prompt a system alert view with undo option. This will not 
be called if 'undoShakingEnabled' is set to NO and/or if the text view's 
content is empty.
+ */
+- (void)willRequestUndo;
+
+/**
+ Notifies the view controller when the user has pressed the Return key (↵) 
with an external keyboard.
+ You can override this method to perform additional tasks.
+ You MUST call super at some point in your implementation.
+ */
+- (void)didPressReturnKey:(id)sender NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller when the user has pressed the Escape key (Esc) 
with an external keyboard.
+ You can override this method to perform additional tasks.
+ You MUST call super at some point in your implementation.
+ */
+- (void)didPressEscapeKey:(id)sender NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller when the user has pressed the arrow key with an 
external keyboard.
+ You can override this method to perform additional tasks.
+ You MUST call super at some point in your implementation.
+ */
+- (void)didPressArrowKey:(id)sender NS_REQUIRES_SUPER;
+
+
+#pragma mark - Text Input Bar Adjustment
+///------------------------------------------------
+/// @name Text Input Bar Adjustment
+///------------------------------------------------
+
+/** YES if the text inputbar is hidden. Default is NO. */
+@property (nonatomic, getter=isTextInputbarHidden) BOOL textInputbarHidden;
+
+/**
+ Changes the visibility of the text input bar.
+ Calling this method with the animated parameter set to NO is equivalent to 
setting the value of the toolbarHidden property directly.
+ 
+ @param hidden Specify YES to hide the toolbar or NO to show it.
+ @param animated Specify YES if you want the toolbar to be animated on or off 
the screen.
+ */
+- (void)setTextInputbarHidden:(BOOL)hidden animated:(BOOL)animated;
+
+
+#pragma mark - Text Edition
+///------------------------------------------------
+/// @name Text Edition
+///------------------------------------------------
+
+/** YES if the text editing mode is active. */
+@property (nonatomic, readonly, getter = isEditing) BOOL editing;
+
+/**
+ Re-uses the text layout for edition, displaying an accessory view on top of 
the text input bar with options (cancel & save).
+ You can override this method to perform additional tasks
+ You MUST call super at some point in your implementation.
+ 
+ @param text The string text to edit.
+ */
+- (void)editText:(NSString *)text NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller when the editing bar's right button's action has 
been triggered, manually or by using the external keyboard's Return key.
+ You can override this method to perform additional tasks associated with 
accepting changes.
+ You MUST call super at some point in your implementation.
+ 
+ @param sender The object calling this method.
+ */
+- (void)didCommitTextEditing:(id)sender NS_REQUIRES_SUPER;
+
+/**
+ Notifies the view controller when the editing bar's right button's action has 
been triggered, manually or by using the external keyboard's Esc key.
+ You can override this method to perform additional tasks associated with 
accepting changes.
+ You MUST call super at some point in your implementation.
+ 
+ @param sender The object calling this method.
+ */
+- (void)didCancelTextEditing:(id)sender NS_REQUIRES_SUPER;
+
+
+#pragma mark - Text Auto-Completion
+///------------------------------------------------
+/// @name Text Auto-Completion
+///------------------------------------------------
+
+/** The table view used to display autocompletion results. */
+@property (nonatomic, readonly) UITableView *autoCompletionView;
+
+/** YES if the autocompletion mode is active. */
+@property (nonatomic, readonly, getter = isAutoCompleting) BOOL autoCompleting;
+
+/** The recently found prefix symbol used as prefix for autocompletion mode. */
+@property (nonatomic, readonly, copy) NSString *foundPrefix;
+
+/** The range of the found prefix in the text view content. */
+@property (nonatomic, readonly) NSRange foundPrefixRange;
+
+/** The recently found word at the text view's caret position. */
+@property (nonatomic, readonly, copy) NSString *foundWord;
+
+/** An array containing all the registered prefix strings for autocompletion. 
*/
+@property (nonatomic, readonly, copy) NSArray *registeredPrefixes;
+
+/**
+ Registers any string prefix for autocompletion detection, useful for user 
mentions and/or hashtags autocompletion.
+ The prefix must be valid string (i.e: '@', '#', '\', and so on). This also 
checks if no repeated prefix are inserted.
+ Prefixes can be of any length.
+ 
+ @param prefixes An array of prefix strings.
+ */
+- (void)registerPrefixesForAutoCompletion:(NSArray *)prefixes;
+
+/**
+ Notifies the view controller either the autocompletion prefix or word have 
changed.
+ Use this method to modify your data source or fetch data asynchronously from 
an HTTP resource.
+ Once your data source is ready, make sure to call -showAutoCompletionView: to 
display the view accordingly.
+ You don't need call super since this method doesn't do anything.
+
+ @param prefix The detected prefix.
+ @param word The derected word.
+ */
+- (void)didChangeAutoCompletionPrefix:(NSString *)prefix andWord:(NSString 
*)word;
+
+/**
+ Use this method to programatically show/hide the autocompletion view.
+ Right before the view is shown, -reloadData is called. So avoid calling it 
manually.
+ 
+ @param show YES if the autocompletion view should be shown.
+ */
+- (void)showAutoCompletionView:(BOOL)show;
+
+/**
+ Verifies that the autocompletion view should be shown. Default is NO.
+ To enabled autocompletion, you MUST override this method to perform 
additional tasks, before the autocompletion view is shown (i.e. populating the 
data source).
+ 
+ @return YES if the autocompletion view should be shown.
+ */
+- (BOOL)canShowAutoCompletion DEPRECATED_MSG_ATTRIBUTE("Override 
-didChangeAutoCompletionPrefix:andWord: instead");
+
+/**
+ Returns a custom height for the autocompletion view. Default is 0.0.
+ You can override this method to return a custom height.
+ 
+ @return The autocompletion view's height.
+ */
+- (CGFloat)heightForAutoCompletionView;
+
+/**
+ Returns the maximum height for the autocompletion view. Default is 140 pts.
+ You can override this method to return a custom max height.
+ 
+ @return The autocompletion view's max height.
+ */
+- (CGFloat)maximumHeightForAutoCompletionView;
+
+/**
+ Cancels and hides the autocompletion view, animated.
+ */
+- (void)cancelAutoCompletion;
+
+/**
+ Accepts the autocompletion, replacing the detected word with a new string, 
keeping the prefix.
+ This method is a convinience of -acceptAutoCompletionWithString:keepPrefix:
+ 
+ @param string The string to be used for replacing autocompletion placeholders.
+ */
+- (void)acceptAutoCompletionWithString:(NSString *)string;
+
+/**
+ Accepts the autocompletion, replacing the detected word with a new string, 
and optionally replacing the prefix too.
+ 
+ @param string The string to be used for replacing autocompletion placeholders.
+ @param keepPrefix YES if the prefix shouldn't be overidden.
+ */
+- (void)acceptAutoCompletionWithString:(NSString *)string 
keepPrefix:(BOOL)keepPrefix;
+
+
+#pragma mark - Text Caching
+///------------------------------------------------
+/// @name Text Caching
+///------------------------------------------------
+
+/**
+ Returns the key to be associated with a given text to be cached. Default is 
nil.
+ To enable text caching, you must override this method to return valid key.
+ The text view will be populated automatically when the view controller is 
configured.
+ You don't need to call super since this method doesn't do anything.
+ 
+ @return The string key for which to enable text caching.
+ */
+- (NSString *)keyForTextCaching;
+
+/**
+ Removes the current's vien controller cached text.
+ To enable this, you must return a valid key string in -keyForTextCaching.
+ */
+- (void)clearCachedText;
+
+/**
+ Removes all the cached text from disk.
+ */
++ (void)clearAllCachedText;
+
+
+#pragma mark - Customization
+///------------------------------------------------
+/// @name Customization
+///------------------------------------------------
+
+/**
+ Registers a class for customizing the behavior and appearance of the text 
view.
+ You need to call this method inside of any initialization method.
+ 
+ @param aClass A SLKTextView subclass.
+ */
+- (void)registerClassForTextView:(Class)aClass;
+
+/**
+ Registers a class for customizing the behavior and appearance of the typing 
indicator view.
+ You need to call this method inside of any initialization method.
+ Make sure to conform to SLKTypingIndicatorProtocol and implement the required 
methods.
+ 
+ @param aClass A UIView subclass conforming to the SLKTypingIndicatorProtocol.
+ */
+- (void)registerClassForTypingIndicatorView:(Class)aClass;
+
+
+#pragma mark - Delegate Methods Requiring Super
+///------------------------------------------------
+/// @name Delegate Methods Requiring Super
+///------------------------------------------------
+
+/** UITextViewDelegate */
+- (BOOL)textView:(UITextView *)textView shouldChangeTextInRange:(NSRange)range 
replacementText:(NSString *)text NS_REQUIRES_SUPER;
+
+/** SLKTextViewDelegate */
+- (BOOL)textView:(SLKTextView *)textView 
shouldInsertSuffixForFormattingWithSymbol:(NSString *)symbol 
prefixRange:(NSRange)prefixRange NS_REQUIRES_SUPER;
+
+/** UIScrollViewDelegate */
+- (BOOL)scrollViewShouldScrollToTop:(UIScrollView *)scrollView 
NS_REQUIRES_SUPER;
+- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView 
willDecelerate:(BOOL)decelerate NS_REQUIRES_SUPER;
+- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView 
NS_REQUIRES_SUPER;
+- (void)scrollViewDidScroll:(UIScrollView *)scrollView NS_REQUIRES_SUPER;
+
+/** UIGestureRecognizerDelegate */
+- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer 
NS_REQUIRES_SUPER;
+
+/** UIAlertViewDelegate */
+#ifndef __IPHONE_8_0
+- (void)alertView:(UIAlertView *)alertView 
clickedButtonAtIndex:(NSInteger)buttonIndex NS_REQUIRES_SUPER;
+#endif
+
+#pragma mark - Life Cycle Methods Requiring Super
+///------------------------------------------------
+/// @name Life Cycle Methods Requiring Super
+///------------------------------------------------
+
+/**
+ Configures view hierarchy and layout constraints. If you override these 
methods, make sure to call super.
+ */
+- (void)loadView NS_REQUIRES_SUPER;
+- (void)viewDidLoad NS_REQUIRES_SUPER;
+- (void)viewWillAppear:(BOOL)animated NS_REQUIRES_SUPER;
+- (void)viewDidAppear:(BOOL)animated NS_REQUIRES_SUPER;
+- (void)viewWillDisappear:(BOOL)animated NS_REQUIRES_SUPER;
+- (void)viewDidDisappear:(BOOL)animated NS_REQUIRES_SUPER;
+- (void)viewWillLayoutSubviews NS_REQUIRES_SUPER;
+- (void)viewDidLayoutSubviews NS_REQUIRES_SUPER;
+
+@end

Reply via email to