diff --git a/KILabel/Source/KILabel.h b/KILabel/Source/KILabel.h old mode 100644 new mode 100755 index 74c6cc6..f5fd499 --- a/KILabel/Source/KILabel.h +++ b/KILabel/Source/KILabel.h @@ -46,6 +46,10 @@ typedef NS_ENUM(NSUInteger, KILinkType) * URLs, http etc */ KILinkTypeURL, + /** + * Phones + */ + KILinkTypePhone }; /** @@ -73,6 +77,12 @@ typedef NS_OPTIONS(NSUInteger, KILinkTypeOption) */ KILinkTypeOptionURL = 1 << KILinkTypeURL, + + /** + * Specifies to include KILinkTypePhone links + */ + KILinkTypeOptionPhone = 1 << KILinkTypePhone, + /** * Convenience contstant to include all link types */ @@ -90,6 +100,7 @@ typedef NS_OPTIONS(NSUInteger, KILinkTypeOption) * @param range The range of the string within the label's text */ typedef void (^KILinkTapHandler)(KILabel *label, NSString *string, NSRange range); +typedef void (^KILinkLongTapHandler)(KILabel *label, KILinkType type, NSString *string, NSRange range); extern NSString * const KILabelLinkTypeKey; extern NSString * const KILabelRangeKey; @@ -176,6 +187,16 @@ IB_DESIGNABLE */ @property (nullable, nonatomic, copy) KILinkTapHandler urlLinkTapHandler; +/** + * Callback block for KILinkTypePhone link tap. + */ +@property (nullable, nonatomic, copy) KILinkTapHandler phoneLinkTapHandler; + +/** + * Callback block for long link tap. + */ +@property (nullable, nonatomic, copy) KILinkLongTapHandler linkLongTapHandler; + /** ****************************************************************************************** ** * @name Geometry ** ****************************************************************************************** **/ diff --git a/KILabel/Source/KILabel.m b/KILabel/Source/KILabel.m old mode 100644 new mode 100755 index 37dbbff..185cfbd --- a/KILabel/Source/KILabel.m +++ b/KILabel/Source/KILabel.m @@ -26,12 +26,12 @@ #import "KILabel.h" NSString * const KILabelLinkTypeKey = @"linkType"; -NSString * const KILabelRangeKey = @"range"; -NSString * const KILabelLinkKey = @"link"; +NSString * const KILabelRangeKey = @"range"; +NSString * const KILabelLinkKey = @"link"; #pragma mark - Private Interface -@interface KILabel() +@interface KILabel() < UIGestureRecognizerDelegate > // Used to control layout of glyphs and rendering @property (nonatomic, retain) NSLayoutManager *layoutManager; @@ -40,28 +40,26 @@ @interface KILabel() @property (nonatomic, retain) NSTextContainer *textContainer; // Backing storage for text that is rendered by the layout manager -@property (nonatomic, retain) NSTextStorage *textStorage; +@property (nonatomic, retain) NSTextStorage *textStorage; // Dictionary of detected links and their ranges in the text -@property (nonatomic, copy) NSArray *linkRanges; +@property (nonatomic, copy ) NSArray *linkRanges; // State used to trag if the user has dragged during a touch -@property (nonatomic, assign) BOOL isTouchMoved; +@property (nonatomic, assign) BOOL isTouchMoved; // During a touch, range of text that is displayed as selected -@property (nonatomic, assign) NSRange selectedRange; +@property (nonatomic, assign) NSRange selectedRange; @end #pragma mark - Implementation - @implementation KILabel { NSMutableDictionary *_linkTypeAttributes; } #pragma mark - Construction - - (id)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; @@ -88,14 +86,14 @@ - (id)initWithCoder:(NSCoder *)aDecoder - (void)setupTextSystem { // Create a text container and set it up to match our label properties - _textContainer = [[NSTextContainer alloc] init]; - _textContainer.lineFragmentPadding = 0; + _textContainer = [NSTextContainer new]; + _textContainer.lineFragmentPadding = 0; _textContainer.maximumNumberOfLines = self.numberOfLines; - _textContainer.lineBreakMode = self.lineBreakMode; - _textContainer.size = self.frame.size; - + _textContainer.lineBreakMode = self.lineBreakMode; + _textContainer.size = self.frame.size; + // Create a layout manager for rendering - _layoutManager = [[NSLayoutManager alloc] init]; + _layoutManager = [NSLayoutManager new]; _layoutManager.delegate = self; [_layoutManager addTextContainer:_textContainer]; @@ -103,30 +101,35 @@ - (void)setupTextSystem [_textContainer setLayoutManager:_layoutManager]; // Make sure user interaction is enabled so we can accept touches - self.userInteractionEnabled = YES; - + self.userInteractionEnabled = YES; + // Don't go via public setter as this will have undesired side effect _automaticLinkDetectionEnabled = YES; - + // All links are detectable by default - _linkDetectionTypes = KILinkTypeOptionAll; - + _linkDetectionTypes = KILinkTypeOptionAll; + // Link Type Attributes. Default is empty (no attributes). - _linkTypeAttributes = [NSMutableDictionary dictionary]; - + _linkTypeAttributes = [NSMutableDictionary dictionary]; + // Don't underline URL links by default. - _systemURLStyle = NO; + _systemURLStyle = NO; // By default we hilight the selected link during a touch to give feedback that we are // responding to touch. - _selectedLinkBackgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0]; + _selectedLinkBackgroundColor = [UIColor colorWithWhite:0.95 alpha:1.0]; // Establish the text store with our current text [self updateTextStoreWithText]; + + // attach long press gesture to collectionView + UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; + longPressRecognizer.minimumPressDuration = .5; + longPressRecognizer.delegate = self; + [self addGestureRecognizer:longPressRecognizer]; } #pragma mark - Text and Style management - - (void)setAutomaticLinkDetectionEnabled:(BOOL)decorating { _automaticLinkDetectionEnabled = decorating; @@ -241,7 +244,7 @@ - (void)setSystemURLStyle:(BOOL)systemURLStyle self.text = self.text; } -- (NSDictionary*)attributesForLinkType:(KILinkType)linkType +- (NSDictionary *)attributesForLinkType:(KILinkType)linkType { NSDictionary *attributes = _linkTypeAttributes[@(linkType)]; @@ -269,7 +272,6 @@ - (void)setAttributes:(NSDictionary*)attributes forLinkType:(KILinkType)linkType } #pragma mark - Text Storage Management - - (void)updateTextStoreWithText { // Now update our storage from either the attributedString or the plain text @@ -325,16 +327,16 @@ - (void)updateTextStoreWithAttributedString:(NSAttributedString *)attributedStri - (NSDictionary *)attributesFromProperties { // Setup shadow attributes - NSShadow *shadow = shadow = [[NSShadow alloc] init]; + NSShadow *shadow = shadow = [NSShadow new]; if (self.shadowColor) { - shadow.shadowColor = self.shadowColor; + shadow.shadowColor = self.shadowColor; shadow.shadowOffset = self.shadowOffset; } else { shadow.shadowOffset = CGSizeMake(0, -1); - shadow.shadowColor = nil; + shadow.shadowColor = nil; } // Setup color attributes @@ -350,7 +352,7 @@ - (NSDictionary *)attributesFromProperties // Setup paragraph attributes NSMutableParagraphStyle *paragraph = [[NSMutableParagraphStyle alloc] init]; - paragraph.alignment = self.textAlignment; + paragraph.alignment = self.textAlignment; // Create the dictionary NSDictionary *attributes = @{NSFontAttributeName : self.font, @@ -371,7 +373,7 @@ - (NSDictionary *)attributesFromProperties */ - (NSArray *)getRangesForLinks:(NSAttributedString *)text { - NSMutableArray *rangesForLinks = [[NSMutableArray alloc] init]; + NSMutableArray *rangesForLinks = [NSMutableArray new]; if (self.linkDetectionTypes & KILinkTypeOptionUserHandle) { @@ -388,6 +390,11 @@ - (NSArray *)getRangesForLinks:(NSAttributedString *)text [rangesForLinks addObjectsFromArray:[self getRangesForURLs:self.attributedText]]; } + if (self.linkDetectionTypes & KILinkTypeOptionPhone) + { + [rangesForLinks addObjectsFromArray:[self getRangesForPhones:self.attributedText]]; + } + return rangesForLinks; } @@ -463,10 +470,9 @@ - (NSArray *)getRangesForURLs:(NSAttributedString *)text NSMutableArray *rangesForURLs = [[NSMutableArray alloc] init];; // Use a data detector to find urls in the text - NSError *error = nil; + NSError *error = nil; NSDataDetector *detector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypeLink error:&error]; - - NSString *plainText = text.string; + NSString *plainText = text.string; NSArray *matches = [detector matchesInString:plainText options:0 @@ -479,7 +485,7 @@ - (NSArray *)getRangesForURLs:(NSAttributedString *)text // If there's a link embedded in the attributes, use that instead of the raw text NSString *realURL = [text attribute:NSLinkAttributeName atIndex:matchRange.location effectiveRange:nil]; - if (realURL == nil) + if (!realURL) realURL = [plainText substringWithRange:matchRange]; if (![self ignoreMatch:realURL]) @@ -497,6 +503,37 @@ - (NSArray *)getRangesForURLs:(NSAttributedString *)text return rangesForURLs; } +- (NSArray *)getRangesForPhones:(NSAttributedString *)text +{ + NSMutableArray *rangesForPhones = [NSMutableArray new]; + + // Use a data detector to find phones in the text + NSError *error = nil; + NSDataDetector *detector = [[NSDataDetector alloc] initWithTypes:NSTextCheckingTypePhoneNumber + error:&error]; + NSString *plainText = text.string; + NSArray *matches = [detector matchesInString:plainText + options:0 + range:NSMakeRange(0, text.length)]; + + // Add a range entry for every phone we found + for (NSTextCheckingResult *match in matches) + { + NSRange matchRange = [match range]; + NSString *matchString = [plainText substringWithRange:matchRange]; + + if (![self ignoreMatch:matchString]) + { + [rangesForPhones addObject:@{KILabelLinkTypeKey : @(KILinkTypePhone), + KILabelRangeKey : [NSValue valueWithRange:matchRange], + KILabelLinkKey : matchString, + }]; + } + } + + return rangesForPhones; +} + - (BOOL)ignoreMatch:(NSString*)string { return [_ignoredKeywords containsObject:[string lowercaseString]]; @@ -508,9 +545,8 @@ - (NSAttributedString *)addLinkAttributesToAttributedString:(NSAttributedString for (NSDictionary *dictionary in linkRanges) { - NSRange range = [[dictionary objectForKey:KILabelRangeKey] rangeValue]; - KILinkType linkType = [dictionary[KILabelLinkTypeKey] unsignedIntegerValue]; - + NSRange range = [[dictionary objectForKey:KILabelRangeKey] rangeValue]; + KILinkType linkType = [dictionary[KILabelLinkTypeKey] unsignedIntegerValue]; NSDictionary *attributes = [self attributesForLinkType:linkType]; // Use our tint color to hilight the link @@ -528,24 +564,23 @@ - (NSAttributedString *)addLinkAttributesToAttributedString:(NSAttributedString } #pragma mark - Layout and Rendering - - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)numberOfLines { // Use our text container to calculate the bounds required. First save our // current text container setup - CGSize savedTextContainerSize = _textContainer.size; + CGSize savedTextContainerSize = _textContainer.size; NSInteger savedTextContainerNumberOfLines = _textContainer.maximumNumberOfLines; // Apply the new potential bounds and number of lines - _textContainer.size = bounds.size; + _textContainer.size = bounds.size; _textContainer.maximumNumberOfLines = numberOfLines; // Measure the text with the new state CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer]; // Position the bounds and round up the size for good measure - textBounds.origin = bounds.origin; - textBounds.size.width = ceil(textBounds.size.width); + textBounds.origin = bounds.origin; + textBounds.size.width = ceil(textBounds.size.width); textBounds.size.height = ceil(textBounds.size.height); if (textBounds.size.height < bounds.size.height) @@ -556,7 +591,7 @@ - (CGRect)textRectForBounds:(CGRect)bounds limitedToNumberOfLines:(NSInteger)num } // Restore the old container state before we exit under any circumstances - _textContainer.size = savedTextContainerSize; + _textContainer.size = savedTextContainerSize; _textContainer.maximumNumberOfLines = savedTextContainerNumberOfLines; return textBounds; @@ -569,7 +604,7 @@ - (void)drawTextInRect:(CGRect)rect // [super drawTextInRect:rect]; // Calculate the offset of the text in the view - NSRange glyphRange = [_layoutManager glyphRangeForTextContainer:_textContainer]; + NSRange glyphRange = [_layoutManager glyphRangeForTextContainer:_textContainer]; CGPoint glyphsPosition = [self calcGlyphsPositionInView]; // Drawing code @@ -582,14 +617,14 @@ - (CGPoint)calcGlyphsPositionInView { CGPoint textOffset = CGPointZero; - CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer]; - textBounds.size.width = ceil(textBounds.size.width); + CGRect textBounds = [_layoutManager usedRectForTextContainer:_textContainer]; + textBounds.size.width = ceil(textBounds.size.width); textBounds.size.height = ceil(textBounds.size.height); if (textBounds.size.height < self.bounds.size.height) { CGFloat paddingHeight = (self.bounds.size.height - textBounds.size.height) / 2.0; - textOffset.y = paddingHeight; + textOffset.y = paddingHeight; } return textOffset; @@ -598,21 +633,18 @@ - (CGPoint)calcGlyphsPositionInView - (void)setFrame:(CGRect)frame { [super setFrame:frame]; - _textContainer.size = self.bounds.size; } - (void)setBounds:(CGRect)bounds { [super setBounds:bounds]; - _textContainer.size = self.bounds.size; } - (void)layoutSubviews { [super layoutSubviews]; - // Update our container size when the view frame changes _textContainer.size = self.bounds.size; } @@ -629,7 +661,6 @@ - (void)setIgnoredKeywords:(NSSet *)ignoredKeywords } #pragma mark - Interactions - - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { _isTouchMoved = NO; @@ -637,7 +668,7 @@ - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event // Get the info for the touched link if there is one NSDictionary *touchedLink; CGPoint touchLocation = [[touches anyObject] locationInView:self]; - touchedLink = [self linkAtPoint:touchLocation]; + touchedLink = [self linkAtPoint:touchLocation]; if (touchedLink) { @@ -664,20 +695,19 @@ - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event if (_isTouchMoved) { self.selectedRange = NSMakeRange(0, 0); - return; } // Get the info for the touched link if there is one NSDictionary *touchedLink; CGPoint touchLocation = [[touches anyObject] locationInView:self]; - touchedLink = [self linkAtPoint:touchLocation]; + touchedLink = [self linkAtPoint:touchLocation]; if (touchedLink) { - NSRange range = [[touchedLink objectForKey:KILabelRangeKey] rangeValue]; + NSRange range = [[touchedLink objectForKey:KILabelRangeKey] rangeValue]; NSString *touchedSubstring = [touchedLink objectForKey:KILabelLinkKey]; - KILinkType linkType = (KILinkType)[[touchedLink objectForKey:KILabelLinkTypeKey] intValue]; + KILinkType linkType = (KILinkType)[[touchedLink objectForKey:KILabelLinkTypeKey] intValue]; [self receivedActionForLinkType:linkType string:touchedSubstring range:range]; } @@ -701,31 +731,65 @@ - (void)receivedActionForLinkType:(KILinkType)linkType string:(NSString*)string { switch (linkType) { - case KILinkTypeUserHandle: - if (_userHandleLinkTapHandler) - { - _userHandleLinkTapHandler(self, string, range); - } - break; - - case KILinkTypeHashtag: - if (_hashtagLinkTapHandler) - { - _hashtagLinkTapHandler(self, string, range); - } - break; - - case KILinkTypeURL: - if (_urlLinkTapHandler) - { - _urlLinkTapHandler(self, string, range); - } - break; + case KILinkTypeUserHandle: + if (_userHandleLinkTapHandler) + { + _userHandleLinkTapHandler(self, string, range); + } + break; + + case KILinkTypeHashtag: + if (_hashtagLinkTapHandler) + { + _hashtagLinkTapHandler(self, string, range); + } + break; + + case KILinkTypeURL: + if (_urlLinkTapHandler) + { + _urlLinkTapHandler(self, string, range); + } + break; + case KILinkTypePhone: + if (_phoneLinkTapHandler) + { + _phoneLinkTapHandler(self, string, range); + } } } -#pragma mark - Layout manager delegate +- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer +{ + if (!_linkLongTapHandler) { + return; + } + + // Only accept gestures on our label and only in the begin state + if ((recognizer.view != self) || (recognizer.state != UIGestureRecognizerStateBegan)) + { + return; + } + + // Get the position of the touch in the label + CGPoint location = [recognizer locationInView:self]; + + // Get the link under the location from the label + NSDictionary *link = [self linkAtPoint:location]; + + if (!link) + { + return; + } + NSRange range = [[link objectForKey:KILabelRangeKey] rangeValue]; + NSString *touchedSubstring = [link objectForKey:KILabelLinkKey]; + KILinkType linkType = (KILinkType)[[link objectForKey:KILabelLinkTypeKey] intValue]; + + _linkLongTapHandler(self, linkType, touchedSubstring, range); +} + +#pragma mark - Layout manager delegate -(BOOL)layoutManager:(NSLayoutManager *)layoutManager shouldBreakLineByWordBeforeCharacterAtIndex:(NSUInteger)charIndex { // Don't allow line breaks inside URLs @@ -755,7 +819,7 @@ + (NSAttributedString *)sanitizeAttributedString:(NSAttributedString *)attribute // Remove the line breaks NSMutableParagraphStyle *mutableParagraphStyle = [paragraphStyle mutableCopy]; - mutableParagraphStyle.lineBreakMode = NSLineBreakByWordWrapping; + mutableParagraphStyle.lineBreakMode = NSLineBreakByWordWrapping; // Apply new style NSMutableAttributedString *restyled = [[NSMutableAttributedString alloc] initWithAttributedString:attributedString]; diff --git a/KILabelDemo/KILabelDemo/Base.lproj/Main.storyboard b/KILabelDemo/KILabelDemo/Base.lproj/Main.storyboard old mode 100644 new mode 100755 index 1279791..38f2811 --- a/KILabelDemo/KILabelDemo/Base.lproj/Main.storyboard +++ b/KILabelDemo/KILabelDemo/Base.lproj/Main.storyboard @@ -1,7 +1,7 @@ - + - + @@ -16,87 +16,102 @@ - @@ -116,11 +131,6 @@ - - - - - diff --git a/KILabelDemo/KILabelDemo/KILabelTableViewController.m b/KILabelDemo/KILabelDemo/KILabelTableViewController.m index 27417bf..f012883 100644 --- a/KILabelDemo/KILabelDemo/KILabelTableViewController.m +++ b/KILabelDemo/KILabelDemo/KILabelTableViewController.m @@ -7,13 +7,12 @@ // #import "KILabelTableViewController.h" - #import "KILabelTableViewCell.h" NSString * const KILabelCellIdentifier = @"labelCell"; @implementation KILabelTableViewController - +#pragma mark - LifeCycle /** * When the view loads we set the estimated row height to a non-zero value. This will mean * that the row height will be calculated for us by auto-layout when each row comes into view. @@ -21,12 +20,10 @@ @implementation KILabelTableViewController - (void)viewDidLoad { [super viewDidLoad]; - self.tableView.estimatedRowHeight = 44; } #pragma mark - Table view data source - /** * Just one section in our table. */ @@ -68,7 +65,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N break; case 1: - cell.label.text = @"Here's an #emoji, one of the joys of unicode strings! 😈"; + cell.label.text = @"Here's an #emoji, one of the joys of unicode strings! 😈 Some number: +380665593617"; break; case 2: @@ -88,8 +85,9 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N }; cell.label.userHandleLinkTapHandler = tapHandler; - cell.label.urlLinkTapHandler = tapHandler; - cell.label.hashtagLinkTapHandler = tapHandler; + cell.label.urlLinkTapHandler = tapHandler; + cell.label.hashtagLinkTapHandler = tapHandler; + cell.label.phoneLinkTapHandler = tapHandler; return cell; } @@ -102,7 +100,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N */ - (void)tappedLink:(NSString *)link cellForRowAtIndexPath:(NSIndexPath *)indexPath { - NSString *title = [NSString stringWithFormat:@"Tapped %@", link]; + NSString *title = [NSString stringWithFormat:@"Tapped %@", link]; NSString *message = [NSString stringWithFormat:@"You tapped %@ in section %@, row %@.", link, @(indexPath.section), @@ -111,8 +109,8 @@ - (void)tappedLink:(NSString *)link cellForRowAtIndexPath:(NSIndexPath *)indexPa UIAlertController *alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]]; + [alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; } diff --git a/KILabelDemo/KILabelDemo/KIViewController.h b/KILabelDemo/KILabelDemo/KIViewController.h old mode 100644 new mode 100755 diff --git a/KILabelDemo/KILabelDemo/KIViewController.m b/KILabelDemo/KILabelDemo/KIViewController.m old mode 100644 new mode 100755 index 908728f..36fc77b --- a/KILabelDemo/KILabelDemo/KIViewController.m +++ b/KILabelDemo/KILabelDemo/KIViewController.m @@ -26,34 +26,31 @@ #import "KIViewController.h" #import "KILabel.h" - @interface KIViewController () @property (weak, nonatomic) IBOutlet KILabel *label; - - (IBAction)toggleDetectLinks:(UISwitch *)sender; - (IBAction)toggleDetectURLs:(UISwitch *)sender; - (IBAction)toggleDetectUsernames:(UISwitch *)sender; - (IBAction)toggleDetectHashtags:(UISwitch *)sender; -- (IBAction)longPressLabel:(UILongPressGestureRecognizer *)sender; @end @implementation KIViewController - /** * When the view loads we attach handlers for the events we're interested in. KILabel differenciates * between taps on different types of link. */ +#pragma mark - LifeCycle - (void)viewDidLoad { [super viewDidLoad]; _label.systemURLStyle = YES; - + // Attach block for handling taps on usenames _label.userHandleLinkTapHandler = ^(KILabel *label, NSString *string, NSRange range) { - NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; + NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Username" message:message preferredStyle:UIAlertControllerStyleAlert]; @@ -61,9 +58,9 @@ - (void)viewDidLoad [self presentViewController:alert animated:YES completion:nil]; }; - + _label.hashtagLinkTapHandler = ^(KILabel *label, NSString *string, NSRange range) { - NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; + NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Hashtag" message:message preferredStyle:UIAlertControllerStyleAlert]; @@ -76,58 +73,71 @@ - (void)viewDidLoad // Open URLs [self attemptOpenURL:[NSURL URLWithString:string]]; }; -} - -#pragma mark - Action Targets - -/** - * Handler for the user doing a "Long Press" gesture. This is configured in the - * storyboard by a gesture handler attached to the label. - * - * @param recognizer The gestrure recognizer - */ -- (IBAction)longPressLabel:(UILongPressGestureRecognizer *)recognizer -{ - // Only accept gestures on our label and only in the begin state - if ((recognizer.view != self.label) || (recognizer.state != UIGestureRecognizerStateBegan)) - { - return; - } - // Get the position of the touch in the label - CGPoint location = [recognizer locationInView:self.label]; - - // Get the link under the location from the label - NSDictionary *link = [self.label linkAtPoint:location]; + _label.phoneLinkTapHandler = ^(KILabel *label, NSString *string, NSRange range) { + NSString *message = [NSString stringWithFormat:@"You tapped %@", string]; + UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Phone" + message:message + preferredStyle:UIAlertControllerStyleAlert]; + + [alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]]; + [self presentViewController:alert animated:YES completion:nil]; + }; - if (!link) + /** + * Handler for the user doing a "Long Press" gesture. + */ + _label.linkLongTapHandler = ^(KILabel *label, KILinkType type, NSString *string, NSRange range) { - // No link was touched - return; - } - - // Put up an action sheet to let the user do something with the link - UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil message:nil preferredStyle:UIAlertControllerStyleActionSheet]; - [actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; - - [actionSheet addAction:[UIAlertAction actionWithTitle:@"Copy link" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - // Copy straight to the pasteboard - [UIPasteboard generalPasteboard].string = link[KILabelLinkKey]; - }]]; - - [actionSheet addAction:[UIAlertAction actionWithTitle:@"Mail link" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - [self mailLink:link[KILabelLinkKey]]; - }]]; - - [actionSheet addAction:[UIAlertAction actionWithTitle:@"Open in Safari" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { - NSURL *url = [NSURL URLWithString:link[KILabelLinkKey]]; - [self attemptOpenURL:url]; - }]]; - - // Show the action sheet - [self presentViewController:actionSheet animated:YES completion:nil]; + + UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:nil + message:nil + preferredStyle:UIAlertControllerStyleActionSheet]; + switch (type) + { + case KILinkTypeUserHandle: + { + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; + break; + } + case KILinkTypeHashtag: + { + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; + break; + } + case KILinkTypeURL: + { + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; + + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Copy link" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [UIPasteboard generalPasteboard].string = string; + }]]; + + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Mail link" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [self mailLink:string]; + }]]; + + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Open in Safari" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + NSURL *url = [NSURL URLWithString:string]; + [self attemptOpenURL:url]; + }]]; + break; + } + case KILinkTypePhone: + { + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]]; + [actionSheet addAction:[UIAlertAction actionWithTitle:@"Call Phone" style:UIAlertActionStyleDefault handler:^(UIAlertAction *action) { + [[UIApplication sharedApplication] openURL:[NSURL URLWithString:string]]; + }]]; + break; + } + } + + [self presentViewController:actionSheet animated:YES completion:nil]; + }; } +#pragma mark - Action Targets /** * Action method for toggling all link detection. * @@ -189,15 +199,31 @@ - (IBAction)toggleDetectHashtags:(UISwitch *)sender } } +/** + * Action method to demonstrate toggling of Phones hilighting and hit detection. + * + * @param sender Switch action is bound to + */ +- (IBAction)toogleDetectPhones:(UISwitch *)sender +{ + if (sender.isOn) + { + self.label.linkDetectionTypes |= KILinkTypeOptionPhone; + } + else + { + self.label.linkDetectionTypes ^= KILinkTypeOptionPhone; + } +} #pragma mark - Helper methods - /** * Checks to see if its an URL that we can open in safari. If we can then open it, * otherwise put up an alert to the user. * * @param url URL to open in Safari */ + - (void)attemptOpenURL:(NSURL *)url { BOOL safariCompatible = [url.scheme isEqualToString:@"http"] || [url.scheme isEqualToString:@"https"]; @@ -243,8 +269,8 @@ - (void)mailLink:(NSString *)link UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Problem" message:@"Cannot send mail." preferredStyle:UIAlertControllerStyleAlert]; - [alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]]; + [alert addAction:[UIAlertAction actionWithTitle:@"Dismiss" style:UIAlertActionStyleDefault handler:nil]]; [self presentViewController:alert animated:YES completion:nil]; } } @@ -258,6 +284,7 @@ @implementation KIViewController (MFMailComposeViewControllerDelegate) /** * Just dismiss the controller. Don't do anything else. */ + -(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error { [self dismissViewControllerAnimated:YES completion:NULL]; diff --git a/README.md b/README.md index 64b7b38..f485aa9 100644 --- a/README.md +++ b/README.md @@ -113,3 +113,9 @@ Any otherfeedback welcome through the obvious channels. - http://compiledcreations.com - http://twitter.com/krelborn - http://github.com/krelborn + + +# From Me : +In this fork You have some additional things: +- Phones +- LongTaps