diff --git a/clients/ios/Classes/ActivityCell.h b/clients/ios/Classes/ActivityCell.h index 78552154e..78dedb062 100644 --- a/clients/ios/Classes/ActivityCell.h +++ b/clients/ios/Classes/ActivityCell.h @@ -7,10 +7,9 @@ // #import -#import "OHAttributedLabel.h" @interface ActivityCell : UITableViewCell { - OHAttributedLabel *activityLabel; + UILabel *activityLabel; UIImageView *faviconView; int topMargin; int bottomMargin; @@ -19,7 +18,7 @@ int avatarSize; } -@property (nonatomic, strong) OHAttributedLabel *activityLabel; +@property (nonatomic, strong) UILabel *activityLabel; @property (nonatomic, strong) UIImageView *faviconView; @property (readwrite) int topMargin; @property (readwrite) int bottomMargin; diff --git a/clients/ios/Classes/ActivityCell.m b/clients/ios/Classes/ActivityCell.m index 74e09634d..5121a50b9 100644 --- a/clients/ios/Classes/ActivityCell.m +++ b/clients/ios/Classes/ActivityCell.m @@ -7,7 +7,6 @@ // #import "ActivityCell.h" -#import "NSAttributedString+Attributes.h" #import "UIImageView+AFNetworking.h" @implementation ActivityCell @@ -31,9 +30,8 @@ self.faviconView = favicon; [self.contentView addSubview:favicon]; - OHAttributedLabel *activity = [[OHAttributedLabel alloc] initWithFrame:CGRectZero]; + UILabel *activity = [[UILabel alloc] initWithFrame:CGRectZero]; activity.backgroundColor = [UIColor whiteColor]; - activity.automaticallyAddLinksForType = NO; self.activityLabel = activity; [self.contentView addSubview:activity]; @@ -61,13 +59,16 @@ labelRect.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin; labelRect.size.height = contentRect.size.height - topMargin - bottomMargin; self.activityLabel.frame = labelRect; + [self.activityLabel sizeToFit]; } - (int)setActivity:(NSDictionary *)activity withUserProfile:(NSDictionary *)userProfile withWidth:(int)width { - // must set the height again for dynamic height in heightForRowAtIndexPath in + // must set the height again for dynamic height in heightForRowAtIndexPath in CGRect activityLabelRect = self.activityLabel.bounds; activityLabelRect.size.width = width - leftMargin - avatarSize - leftMargin - rightMargin; + self.activityLabel.frame = activityLabelRect; + self.activityLabel.numberOfLines = 0; self.faviconView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize); NSString *category = [activity objectForKey:@"category"]; @@ -120,15 +121,15 @@ txt = [NSString stringWithFormat:@"%@ followed %@.", username, withUserUsername]; } else if ([category isEqualToString:@"comment_reply"]) { withUserUsername = [[activity objectForKey:@"with_user"] objectForKey:@"username"]; - txt = [NSString stringWithFormat:@"%@ replied to %@: \n%@", username, withUserUsername, comment]; + txt = [NSString stringWithFormat:@"%@ replied to %@: \n \n%@", username, withUserUsername, comment]; } else if ([category isEqualToString:@"comment_like"]) { withUserUsername = [[activity objectForKey:@"with_user"] objectForKey:@"username"]; - txt = [NSString stringWithFormat:@"%@ favorited %@'s comment on %@:\n%@", username, withUserUsername, title, comment]; + txt = [NSString stringWithFormat:@"%@ favorited %@'s comment on %@:\n \n%@", username, withUserUsername, title, comment]; } else if ([category isEqualToString:@"sharedstory"]) { if ([content class] == [NSNull class] || [content isEqualToString:@""] || content == nil) { txt = [NSString stringWithFormat:@"%@ shared %@.", username, title]; } else { - txt = [NSString stringWithFormat:@"%@ shared %@:\n%@", username, title, comment]; + txt = [NSString stringWithFormat:@"%@ shared %@:\n \n%@", username, title, comment]; } } else if ([category isEqualToString:@"star"]) { @@ -139,38 +140,60 @@ txt = [NSString stringWithFormat:@"You signed up for NewsBlur."]; } - NSString *txtWithTime = [NSString stringWithFormat:@"%@\n%@", txt, time]; - NSMutableAttributedString* attrStr = [NSMutableAttributedString attributedStringWithString:txtWithTime]; + NSString *txtWithTime = [NSString stringWithFormat:@"%@\n \n%@", txt, time]; + NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString:txtWithTime]; - // for those calls we don't specify a range so it affects the whole string - [attrStr setFont:[UIFont fontWithName:@"Helvetica" size:14]]; - [attrStr setTextColor:UIColorFromRGB(0x333333)]; + [attrStr setAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:13]} range:NSMakeRange(0, [txtWithTime length])]; + if (self.highlighted) { + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0xffffff)} range:NSMakeRange(0, [txtWithTime length])]; + } else { + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x333333)} range:NSMakeRange(0, [txtWithTime length])]; + } if (![username isEqualToString:@"You"]){ - [attrStr setTextColor:UIColorFromRGB(NEWSBLUR_LINK_COLOR) range:[txtWithTime rangeOfString:username]]; - [attrStr setTextBold:YES range:[txt rangeOfString:username]]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(NEWSBLUR_LINK_COLOR)} range:[txtWithTime rangeOfString:username]]; + [attrStr addAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13]} range:[txtWithTime rangeOfString:username]]; + } + if (withUserUsername.length) { + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(NEWSBLUR_LINK_COLOR)} range:[txtWithTime rangeOfString:withUserUsername]]; + [attrStr addAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13]} range:[txtWithTime rangeOfString:withUserUsername]]; + } + + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(NEWSBLUR_LINK_COLOR)} range:[txtWithTime rangeOfString:title]]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x666666)} range:[txtWithTime rangeOfString:comment]]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x999999)} range:[txtWithTime rangeOfString:time]]; + [attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:11]} range:[txtWithTime rangeOfString:time]]; + NSMutableParagraphStyle* style= [NSMutableParagraphStyle new]; + style.lineBreakMode = NSLineBreakByWordWrapping; + [attrStr addAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, [txtWithTime length])]; + + NSRange commentRange = [txtWithTime rangeOfString:comment]; + if (commentRange.location != NSNotFound) { + NSLog(@"Spacing: %@", comment); + commentRange.location -= 2; + commentRange.length = 1; + if ([[txtWithTime substringWithRange:commentRange] isEqualToString:@" "]) { + [attrStr addAttribute:NSFontAttributeName + value:[UIFont systemFontOfSize:4.0f] + range:commentRange]; + } } - [attrStr setTextColor:UIColorFromRGB(NEWSBLUR_LINK_COLOR) range:[txtWithTime rangeOfString:title]]; - - if(withUserUsername.length) { - [attrStr setTextColor:UIColorFromRGB(NEWSBLUR_LINK_COLOR) range:[txtWithTime rangeOfString:withUserUsername]]; - [attrStr setTextBold:YES range:[txtWithTime rangeOfString:withUserUsername]]; + NSRange dateRange = [txtWithTime rangeOfString:time]; + if (dateRange.location != NSNotFound) { + dateRange.location -= 2; + dateRange.length = 1; + [attrStr addAttribute:NSFontAttributeName + value:[UIFont systemFontOfSize:4.0f] + range:dateRange]; } - [attrStr setTextColor:UIColorFromRGB(0x666666) range:[txtWithTime rangeOfString:comment]]; - - [attrStr setTextColor:UIColorFromRGB(0x999999) range:[txtWithTime rangeOfString:time]]; - [attrStr setFont:[UIFont fontWithName:@"Helvetica" size:10] range:[txtWithTime rangeOfString:time]]; - [attrStr setTextAlignment:kCTLeftTextAlignment lineBreakMode:kCTLineBreakByWordWrapping lineHeight:4]; - self.activityLabel.attributedText = attrStr; - [self.activityLabel sizeToFit]; - + int height = self.activityLabel.frame.size.height; - return MAX(height, self.faviconView.frame.size.height); + return MAX(height + topMargin + bottomMargin, self.faviconView.frame.size.height); } - (NSString *)stripFormatting:(NSString *)str { diff --git a/clients/ios/Classes/ActivityModule.m b/clients/ios/Classes/ActivityModule.m index 54539e5df..e62031b4d 100644 --- a/clients/ios/Classes/ActivityModule.m +++ b/clients/ios/Classes/ActivityModule.m @@ -24,7 +24,8 @@ @synthesize pageFinished; @synthesize activitiesPage; -#define MINIMUM_ACTIVITY_HEIGHT 48 + 30 +#define MINIMUM_ACTIVITY_HEIGHT_IPAD 78 +#define MINIMUM_ACTIVITY_HEIGHT_IPHONE 54 - (id)initWithFrame:(CGRect)frame { @@ -173,7 +174,11 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { int activitiesCount = [appDelegate.userActivitiesArray count]; if (indexPath.row >= activitiesCount) { - return MINIMUM_ACTIVITY_HEIGHT; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + return MINIMUM_ACTIVITY_HEIGHT_IPAD; + } else { + return MINIMUM_ACTIVITY_HEIGHT_IPHONE; + } } id activityCell; @@ -189,7 +194,7 @@ int height = [activityCell setActivity:[appDelegate.userActivitiesArray objectAtIndex:(indexPath.row)] withUserProfile:userProfile - withWidth:self.frame.size.width - 20] + 30; + withWidth:self.frame.size.width - 20]; return height; @@ -223,8 +228,7 @@ NSString *category = [activitiy objectForKey:@"category"]; if ([category isEqualToString:@"follow"]) { cell.accessoryType = UITableViewCellAccessoryNone; - } else if ([category isEqualToString:@"star"] || - [category isEqualToString:@"signup"]){ + } else if ([category isEqualToString:@"signup"]){ cell.accessoryType = UITableViewCellAccessoryNone; cell.selectionStyle = UITableViewCellSelectionStyleNone; } else { @@ -283,6 +287,12 @@ withUser:[activity objectForKey:@"with_user"] showFindingStory:YES]; appDelegate.tryFeedCategory = category; + } else if ([category isEqualToString:@"star"]) { + NSString *contentIdStr = [NSString stringWithFormat:@"%@", + [activity objectForKey:@"content_id"]]; + [appDelegate loadStarredDetailViewWithStory:contentIdStr + showFindingStory:YES]; + appDelegate.tryFeedCategory = category; } else if ([category isEqualToString:@"feedsub"]) { NSString *feedIdStr = [NSString stringWithFormat:@"%@", [activity objectForKey:@"feed_id"]]; @@ -310,7 +320,12 @@ if (self.pageFinished) { UIImage *img = [UIImage imageNamed:@"fleuron.png"]; UIImageView *fleuron = [[UIImageView alloc] initWithImage:img]; - int height = MINIMUM_ACTIVITY_HEIGHT; + int height; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + height = MINIMUM_ACTIVITY_HEIGHT_IPAD; + } else { + height = MINIMUM_ACTIVITY_HEIGHT_IPHONE; + } fleuron.frame = CGRectMake(0, 0, self.frame.size.width, height); fleuron.contentMode = UIViewContentModeCenter; diff --git a/clients/ios/Classes/FeedDetailViewController.m b/clients/ios/Classes/FeedDetailViewController.m index 7ef842547..f3fa7b2cc 100644 --- a/clients/ios/Classes/FeedDetailViewController.m +++ b/clients/ios/Classes/FeedDetailViewController.m @@ -787,6 +787,7 @@ FeedDetailTableCell *cell = (FeedDetailTableCell *)[self.storyTitlesTable cellForRowAtIndexPath:indexPath]; [self loadStory:cell atRow:indexPath.row]; + [MBProgressHUD hideHUDForView:self.view animated:YES]; // found the story, reset the two flags. // appDelegate.tryFeedStoryId = nil; appDelegate.inFindingStoryMode = NO; @@ -1070,48 +1071,7 @@ [appDelegate calculateStoryLocations]; } - for (int i=0; i < appDelegate.storyLocationsCount; i++) { - int location = [[[appDelegate activeFeedStoryLocations] objectAtIndex:i] intValue]; - NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0]; - NSDictionary *story = [appDelegate.activeFeedStories objectAtIndex:location]; - int score = [NewsBlurAppDelegate computeStoryScore:[story objectForKey:@"intelligence"]]; - - if (previousLevel == -1) { - if (newLevel == 0 && score == -1) { - [deleteIndexPaths addObject:indexPath]; - } else if (newLevel == 1 && score < 1) { - [deleteIndexPaths addObject:indexPath]; - } - } else if (previousLevel == 0) { - if (newLevel == -1 && score == -1) { - [insertIndexPaths addObject:indexPath]; - } else if (newLevel == 1 && score == 0) { - [deleteIndexPaths addObject:indexPath]; - } - } else if (previousLevel == 1) { - if (newLevel == 0 && score == 0) { - [insertIndexPaths addObject:indexPath]; - } else if (newLevel == -1 && score < 1) { - [insertIndexPaths addObject:indexPath]; - } - } - } - - if (newLevel > previousLevel) { - [appDelegate setSelectedIntelligence:newLevel]; - [appDelegate calculateStoryLocations]; - } - - [self.storyTitlesTable beginUpdates]; - if ([deleteIndexPaths count] > 0) { - [self.storyTitlesTable deleteRowsAtIndexPaths:deleteIndexPaths - withRowAnimation:UITableViewRowAnimationNone]; - } - if ([insertIndexPaths count] > 0) { - [self.storyTitlesTable insertRowsAtIndexPaths:insertIndexPaths - withRowAnimation:UITableViewRowAnimationNone]; - } - [self.storyTitlesTable endUpdates]; + [self.storyTitlesTable reloadData]; } - (NSDictionary *)getStoryAtRow:(NSInteger)indexPathRow { diff --git a/clients/ios/Classes/InteractionCell.h b/clients/ios/Classes/InteractionCell.h index 991539f9e..da4fabdb0 100644 --- a/clients/ios/Classes/InteractionCell.h +++ b/clients/ios/Classes/InteractionCell.h @@ -7,10 +7,9 @@ // #import -#import "OHAttributedLabel.h" @interface InteractionCell : UITableViewCell { - OHAttributedLabel *interactionLabel; + UILabel *interactionLabel; UIImageView *avatarView; int topMargin; int bottomMargin; @@ -19,7 +18,7 @@ int avatarSize; } -@property (retain, nonatomic) OHAttributedLabel *interactionLabel; +@property (retain, nonatomic) UILabel *interactionLabel; @property (retain, nonatomic) UIImageView *avatarView; @property (readwrite) int topMargin; @property (readwrite) int bottomMargin; diff --git a/clients/ios/Classes/InteractionCell.m b/clients/ios/Classes/InteractionCell.m index 5d9ca06e7..99a9262a0 100644 --- a/clients/ios/Classes/InteractionCell.m +++ b/clients/ios/Classes/InteractionCell.m @@ -7,8 +7,8 @@ // #import "InteractionCell.h" -#import "NSAttributedString+Attributes.h" #import "UIImageView+AFNetworking.h" +#import @implementation InteractionCell @@ -31,9 +31,9 @@ self.avatarView = avatar; [self.contentView addSubview:avatar]; - OHAttributedLabel *interaction = [[OHAttributedLabel alloc] initWithFrame:CGRectZero]; + UILabel *interaction = [[UILabel alloc] initWithFrame:CGRectZero]; interaction.backgroundColor = [UIColor whiteColor]; - interaction.automaticallyAddLinksForType = NO; +// interaction.automaticallyAddLinksForType = NO; self.interactionLabel = interaction; [self.contentView addSubview:interaction]; @@ -64,6 +64,7 @@ labelRect.size.width = contentRect.size.width - leftMargin - avatarSize - leftMargin - rightMargin; labelRect.size.height = contentRect.size.height - topMargin - bottomMargin; self.interactionLabel.frame = labelRect; + [self.interactionLabel sizeToFit]; } @@ -74,17 +75,16 @@ interactionLabelRect.size.height = 300; self.interactionLabel.frame = interactionLabelRect; + self.interactionLabel.numberOfLines = 0; self.avatarView.frame = CGRectMake(leftMargin, topMargin, avatarSize, avatarSize); -// UIImage *placeholder = [UIImage imageNamed:@"user_light"]; - // this is for the rare instance when the with_user doesn't return anything if ([[interaction objectForKey:@"with_user"] class] == [NSNull class]) { return 1; } [self.avatarView setImageWithURL:[NSURL URLWithString:[[interaction objectForKey:@"with_user"] objectForKey:@"photo_url"]] - placeholderImage:nil]; + placeholderImage:nil ]; NSString *category = [interaction objectForKey:@"category"]; NSString *content = [interaction objectForKey:@"content"]; @@ -97,50 +97,72 @@ if ([category isEqualToString:@"follow"]) { txt = [NSString stringWithFormat:@"%@ is now following you.", username]; } else if ([category isEqualToString:@"comment_reply"]) { - txt = [NSString stringWithFormat:@"%@ replied to your comment on %@:\n%@", username, title, comment]; + txt = [NSString stringWithFormat:@"%@ replied to your comment on %@:\n \n%@", username, title, comment]; } else if ([category isEqualToString:@"reply_reply"]) { - txt = [NSString stringWithFormat:@"%@ replied to your reply on %@:\n%@", username, title, comment]; + txt = [NSString stringWithFormat:@"%@ replied to your reply on %@:\n \n%@", username, title, comment]; } else if ([category isEqualToString:@"story_reshare"]) { if ([content isEqualToString:@""] || content == nil) { txt = [NSString stringWithFormat:@"%@ re-shared %@.", username, title]; } else { - txt = [NSString stringWithFormat:@"%@ re-shared %@:\n%@", username, title, comment]; + txt = [NSString stringWithFormat:@"%@ re-shared %@:\n \n%@", username, title, comment]; } } else if ([category isEqualToString:@"comment_like"]) { - txt = [NSString stringWithFormat:@"%@ favorited your comments on %@:\n%@", username, title, comment]; + txt = [NSString stringWithFormat:@"%@ favorited your comments on %@:\n \n%@", username, title, comment]; } - NSString *txtWithTime = [NSString stringWithFormat:@"%@\n%@", txt, time]; - NSMutableAttributedString* attrStr = [NSMutableAttributedString attributedStringWithString:txtWithTime]; + NSString *txtWithTime = [NSString stringWithFormat:@"%@\n \n%@", txt, time]; + NSMutableAttributedString* attrStr = [[NSMutableAttributedString alloc] initWithString:txtWithTime]; - // for those calls we don't specify a range so it affects the whole string - [attrStr setFont:[UIFont fontWithName:@"Helvetica" size:14]]; + NSMutableParagraphStyle* style = [NSMutableParagraphStyle new]; + style.lineBreakMode = NSLineBreakByWordWrapping; + style.alignment = NSTextAlignmentLeft; + style.lineSpacing = 1.0f; + [attrStr setAttributes:@{NSParagraphStyleAttributeName: style} range:NSMakeRange(0, [txtWithTime length])]; + + [attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:13]} range:NSMakeRange(0, [txtWithTime length])]; if (self.highlighted) { - [attrStr setTextColor:UIColorFromRGB(0xffffff)]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0xffffff)} range:NSMakeRange(0, [txtWithTime length])]; } else { - [attrStr setTextColor:UIColorFromRGB(0x333333)]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x333333)} range:NSMakeRange(0, [txtWithTime length])]; } if (![username isEqualToString:@"You"]){ - [attrStr setTextColor:UIColorFromRGB(NEWSBLUR_LINK_COLOR) range:[txtWithTime rangeOfString:username]]; - [attrStr setTextBold:YES range:[txt rangeOfString:username]]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(NEWSBLUR_LINK_COLOR)} range:[txtWithTime rangeOfString:username]]; + [attrStr addAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:13]} range:[txtWithTime rangeOfString:username]]; + } + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(NEWSBLUR_LINK_COLOR)} range:[txtWithTime rangeOfString:title]]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x666666)} range:[txtWithTime rangeOfString:comment]]; + [attrStr addAttributes:@{NSForegroundColorAttributeName:UIColorFromRGB(0x999999)} range:[txtWithTime rangeOfString:time]]; + + [attrStr addAttributes:@{NSFontAttributeName:[UIFont fontWithName:@"Helvetica" size:11]} range:[txtWithTime rangeOfString:time]]; + + NSRange commentRange = [txtWithTime rangeOfString:comment]; + if (commentRange.location != NSNotFound) { + commentRange.location -= 2; + commentRange.length = 1; + if ([[txtWithTime substringWithRange:commentRange] isEqualToString:@" "]) { + [attrStr addAttribute:NSFontAttributeName + value:[UIFont systemFontOfSize:6.0f] + range:commentRange]; + } } - [attrStr setTextColor:UIColorFromRGB(NEWSBLUR_LINK_COLOR) range:[txtWithTime rangeOfString:title]]; - [attrStr setTextColor:UIColorFromRGB(0x666666) range:[txtWithTime rangeOfString:comment]]; - - [attrStr setTextColor:UIColorFromRGB(0x999999) range:[txtWithTime rangeOfString:time]]; - [attrStr setFont:[UIFont fontWithName:@"Helvetica" size:10] range:[txtWithTime rangeOfString:time]]; - [attrStr setTextAlignment:kCTLeftTextAlignment lineBreakMode:kCTLineBreakByWordWrapping lineHeight:4]; - - self.interactionLabel.attributedText = attrStr; + NSRange dateRange = [txtWithTime rangeOfString:time]; + if (dateRange.location != NSNotFound) { + dateRange.location -= 2; + dateRange.length = 1; + [attrStr addAttribute:NSFontAttributeName + value:[UIFont systemFontOfSize:6.0f] + range:dateRange]; + } + self.interactionLabel.attributedText = attrStr; [self.interactionLabel sizeToFit]; int height = self.interactionLabel.frame.size.height; - return height; + return height + topMargin + bottomMargin; } - (NSString *)stripFormatting:(NSString *)str { diff --git a/clients/ios/Classes/InteractionsModule.m b/clients/ios/Classes/InteractionsModule.m index a774b6c67..0e92cd669 100644 --- a/clients/ios/Classes/InteractionsModule.m +++ b/clients/ios/Classes/InteractionsModule.m @@ -14,7 +14,8 @@ #import "ASIHTTPRequest.h" #import "UserProfileViewController.h" -#define MINIMUM_INTERACTION_HEIGHT 78 +#define MINIMUM_INTERACTION_HEIGHT_IPAD 78 +#define MINIMUM_INTERACTION_HEIGHT_IPHONE 54 @implementation InteractionsModule @@ -175,8 +176,15 @@ - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { int userInteractions = [appDelegate.userInteractionsArray count]; + int minimumHeight; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + minimumHeight = MINIMUM_INTERACTION_HEIGHT_IPAD; + } else { + minimumHeight = MINIMUM_INTERACTION_HEIGHT_IPHONE; + } + if (indexPath.row >= userInteractions) { - return MINIMUM_INTERACTION_HEIGHT; + return minimumHeight; } InteractionCell *interactionCell; @@ -185,9 +193,9 @@ } else { interactionCell = [[SmallInteractionCell alloc] init]; } - int height = [interactionCell setInteraction:[appDelegate.userInteractionsArray objectAtIndex:(indexPath.row)] withWidth:self.frame.size.width - 20] + 30; - if (height < MINIMUM_INTERACTION_HEIGHT) { - return MINIMUM_INTERACTION_HEIGHT; + int height = [interactionCell setInteraction:[appDelegate.userInteractionsArray objectAtIndex:(indexPath.row)] withWidth:self.frame.size.width - 20]; + if (height < minimumHeight) { + return minimumHeight; } else { return height; } @@ -230,6 +238,7 @@ // update the cell information [cell setInteraction:interaction withWidth: self.frame.size.width - 20]; + [cell layoutSubviews]; } return cell; @@ -289,7 +298,13 @@ if (self.pageFinished) { UIImage *img = [UIImage imageNamed:@"fleuron.png"]; UIImageView *fleuron = [[UIImageView alloc] initWithImage:img]; - int height = MINIMUM_INTERACTION_HEIGHT; + + int height; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + height = MINIMUM_INTERACTION_HEIGHT_IPAD; + } else { + height = MINIMUM_INTERACTION_HEIGHT_IPHONE; + } fleuron.frame = CGRectMake(0, 0, self.frame.size.width, height); fleuron.contentMode = UIViewContentModeCenter; diff --git a/clients/ios/Classes/NewsBlurAppDelegate.h b/clients/ios/Classes/NewsBlurAppDelegate.h index 1bfdab833..5281b304c 100644 --- a/clients/ios/Classes/NewsBlurAppDelegate.h +++ b/clients/ios/Classes/NewsBlurAppDelegate.h @@ -270,6 +270,7 @@ - (void)openTrainStory:(id)sender; - (void)loadFeedDetailView; - (void)loadTryFeedDetailView:(NSString *)feedId withStory:(NSString *)contentId isSocial:(BOOL)social withUser:(NSDictionary *)user showFindingStory:(BOOL)showHUD; +- (void)loadStarredDetailViewWithStory:(NSString *)contentId showFindingStory:(BOOL)showHUD; - (void)loadRiverFeedDetailView; - (void)loadStoryDetailView; - (void)adjustStoryDetailWebView; diff --git a/clients/ios/Classes/NewsBlurAppDelegate.m b/clients/ios/Classes/NewsBlurAppDelegate.m index 213e7d7d2..e35032781 100644 --- a/clients/ios/Classes/NewsBlurAppDelegate.m +++ b/clients/ios/Classes/NewsBlurAppDelegate.m @@ -676,7 +676,43 @@ [self loadFeedDetailView]; if (showHUD) { - [self.storyPageControl showShareHUD:@"Finding story..."]; + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + [self.storyPageControl showShareHUD:@"Finding story..."]; + } else { + MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.feedDetailViewController.view animated:YES]; + HUD.labelText = @"Finding story..."; + } + } +} + +- (void)loadStarredDetailViewWithStory:(NSString *)contentId + showFindingStory:(BOOL)showHUD { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { + [self.navigationController popToRootViewControllerAnimated:NO]; + [self.navigationController dismissViewControllerAnimated:YES completion:nil]; + if (self.feedsViewController.popoverController) { + [self.feedsViewController.popoverController dismissPopoverAnimated:NO]; + } + } + + self.isSocialRiverView = NO; + self.isRiverView = YES; + self.inFindingStoryMode = YES; + self.isSocialView = NO; + + self.tryFeedStoryId = contentId; + self.activeFeed = nil; + self.activeFolder = @"saved_stories"; + + [self loadRiverFeedDetailView]; + + if (showHUD) { + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + [self.storyPageControl showShareHUD:@"Finding story..."]; + } else { + MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.feedDetailViewController.view animated:YES]; + HUD.labelText = @"Finding story..."; + } } } @@ -968,6 +1004,7 @@ navController.navigationItem.hidesBackButton = YES; } + [MBProgressHUD hideHUDForView:self.storyPageControl.view animated:YES]; } - (void)navigationController:(UINavigationController *)navController diff --git a/clients/ios/Classes/NewsBlurViewController.m b/clients/ios/Classes/NewsBlurViewController.m index 3b8ad55a2..56dbc470a 100644 --- a/clients/ios/Classes/NewsBlurViewController.m +++ b/clients/ios/Classes/NewsBlurViewController.m @@ -31,6 +31,7 @@ #import "FMDatabaseAdditions.h" #import "IASKAppSettingsViewController.h" #import "IASKSettingsReader.h" +#import "UIImageView+AFNetworking.h" #define kPhoneTableViewRowHeight 31; #define kTableViewRowHeight 31; @@ -550,18 +551,23 @@ static const CGFloat kFolderTitleHeight = 28; // adding user avatar to left NSString *url = [NSString stringWithFormat:@"%@", [[results objectForKey:@"social_profile"] objectForKey:@"photo_url"]]; NSURL * imageURL = [NSURL URLWithString:url]; - NSData * imageData = [NSData dataWithContentsOfURL:imageURL]; - UIImage * userAvatarImage = [UIImage imageWithData:imageData]; - userAvatarImage = [Utilities roundCorneredImage:userAvatarImage radius:6]; UIButton *userAvatarButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation; userAvatarButton.bounds = CGRectMake(0, 0, 32, 32); userAvatarButton.frame = CGRectMake(0, 0, 32, 32); [userAvatarButton addTarget:self action:@selector(showUserProfile) forControlEvents:UIControlEventTouchUpInside]; - [userAvatarButton setImage:userAvatarImage forState:UIControlStateNormal]; UIBarButtonItem *userInfoBarButton = [[UIBarButtonItem alloc] initWithCustomView:userAvatarButton]; + + NSMutableURLRequest *avatarRequest = [NSMutableURLRequest requestWithURL:imageURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0]; + [avatarRequest setHTTPShouldHandleCookies:NO]; + [avatarRequest setHTTPShouldUsePipelining:YES]; + UIImageView *avatarImageView = [[UIImageView alloc] initWithFrame:userAvatarButton.frame]; + [avatarImageView setImageWithURLRequest:avatarRequest placeholderImage:nil success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) { + image = [Utilities roundCorneredImage:image radius:3]; + [userAvatarButton setImage:image forState:UIControlStateNormal]; + } failure:nil]; self.navigationItem.leftBarButtonItem = userInfoBarButton; [self setUserAvatarLayout:orientation]; diff --git a/clients/ios/Classes/SmallActivityCell.m b/clients/ios/Classes/SmallActivityCell.m index bb66f593b..e811e9e0d 100644 --- a/clients/ios/Classes/SmallActivityCell.m +++ b/clients/ios/Classes/SmallActivityCell.m @@ -7,7 +7,6 @@ // #import "SmallActivityCell.h" -#import "NSAttributedString+Attributes.h" #import "UIImageView+AFNetworking.h" #import @@ -24,9 +23,8 @@ self.faviconView = favicon; [self.contentView addSubview:favicon]; - OHAttributedLabel *activity = [[OHAttributedLabel alloc] initWithFrame:CGRectZero]; + UILabel *activity = [[UILabel alloc] initWithFrame:CGRectZero]; activity.backgroundColor = [UIColor whiteColor]; - activity.automaticallyAddLinksForType = NO; self.activityLabel = activity; [self.contentView addSubview:activity]; @@ -62,6 +60,7 @@ self.activityLabel.backgroundColor = UIColorFromRGB(0xf6f6f6); } self.activityLabel.backgroundColor = [UIColor clearColor]; + [self.activityLabel sizeToFit]; } @end diff --git a/clients/ios/Classes/SmallInteractionCell.m b/clients/ios/Classes/SmallInteractionCell.m index 11feca18c..fc63a0533 100644 --- a/clients/ios/Classes/SmallInteractionCell.m +++ b/clients/ios/Classes/SmallInteractionCell.m @@ -7,7 +7,6 @@ // #import "SmallInteractionCell.h" -#import "NSAttributedString+Attributes.h" #import "UIImageView+AFNetworking.h" #import @@ -24,9 +23,8 @@ self.avatarView = favicon; [self.contentView addSubview:favicon]; - OHAttributedLabel *interaction = [[OHAttributedLabel alloc] initWithFrame:CGRectZero]; + UILabel *interaction = [[UILabel alloc] initWithFrame:CGRectZero]; interaction.backgroundColor = [UIColor whiteColor]; - interaction.automaticallyAddLinksForType = NO; self.interactionLabel = interaction; [self.contentView addSubview:interaction]; @@ -62,6 +60,7 @@ self.interactionLabel.backgroundColor = UIColorFromRGB(0xf6f6f6); } self.interactionLabel.backgroundColor = [UIColor clearColor]; + [self.interactionLabel sizeToFit]; } @end diff --git a/clients/ios/Entitlements.entitlements b/clients/ios/Entitlements.entitlements index fe238e5c4..c468210c7 100644 --- a/clients/ios/Entitlements.entitlements +++ b/clients/ios/Entitlements.entitlements @@ -5,7 +5,7 @@ application-identifier $(AppIdentifierPrefix)$(CFBundleIdentifier) get-task-allow - + keychain-access-groups $(AppIdentifierPrefix)$(CFBundleIdentifier) diff --git a/clients/ios/NSAttributedString+Attributes.h b/clients/ios/NSAttributedString+Attributes.h deleted file mode 100644 index f41e97780..000000000 --- a/clients/ios/NSAttributedString+Attributes.h +++ /dev/null @@ -1,80 +0,0 @@ -/*********************************************************************************** - * - * Copyright (c) 2010 Olivier Halligon - * - * 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. - * - *********************************************************************************** - * - * Created by Olivier Halligon (AliSoftware) on 20 Jul. 2010. - * - * Any comment or suggestion welcome. Please contact me before using this class in - * your projects. Referencing this project in your AboutBox/Credits is appreciated. - * - ***********************************************************************************/ - - -#import -#import -#import - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: NSAttributedString Additions -///////////////////////////////////////////////////////////////////////////// - -@interface NSAttributedString (OHCommodityConstructors) -+(id)attributedStringWithString:(NSString*)string; -+(id)attributedStringWithAttributedString:(NSAttributedString*)attrStr; - -//! Commodity method that call the following sizeConstrainedToSize:fitRange: method with NULL for the fitRange parameter --(CGSize)sizeConstrainedToSize:(CGSize)maxSize; -//! if fitRange is not NULL, on return it will contain the used range that actually fits the constrained size. -//! Note: Use CGFLOAT_MAX for the CGSize's height if you don't want a constraint for the height. --(CGSize)sizeConstrainedToSize:(CGSize)maxSize fitRange:(NSRange*)fitRange; -@end - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: NSMutableAttributedString Additions -///////////////////////////////////////////////////////////////////////////// - -@interface NSMutableAttributedString (OHCommodityStyleModifiers) --(void)setFont:(UIFont*)font; --(void)setFont:(UIFont*)font range:(NSRange)range; --(void)setFontName:(NSString*)fontName size:(CGFloat)size; --(void)setFontName:(NSString*)fontName size:(CGFloat)size range:(NSRange)range; --(void)setFontFamily:(NSString*)fontFamily size:(CGFloat)size bold:(BOOL)isBold italic:(BOOL)isItalic range:(NSRange)range; - --(void)setTextColor:(UIColor*)color; --(void)setTextColor:(UIColor*)color range:(NSRange)range; --(void)setTextIsUnderlined:(BOOL)underlined; --(void)setTextIsUnderlined:(BOOL)underlined range:(NSRange)range; --(void)setTextUnderlineStyle:(int32_t)style range:(NSRange)range; //!< style is a combination of CTUnderlineStyle & CTUnderlineStyleModifiers --(void)setTextBold:(BOOL)isBold range:(NSRange)range; - --(void)setTextAlignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode; --(void)setTextAlignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode lineHeight:(CGFloat)lineHeight; --(void)setTextAlignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode range:(NSRange)range; --(void)setTextAlignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode range:(NSRange)range lineHeight:(CGFloat)lineHeight; -@end - - diff --git a/clients/ios/NSAttributedString+Attributes.m b/clients/ios/NSAttributedString+Attributes.m deleted file mode 100644 index 238b4ec26..000000000 --- a/clients/ios/NSAttributedString+Attributes.m +++ /dev/null @@ -1,185 +0,0 @@ -/*********************************************************************************** - * - * Copyright (c) 2010 Olivier Halligon - * - * 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. - * - *********************************************************************************** - * - * Created by Olivier Halligon (AliSoftware) on 20 Jul. 2010. - * - * Any comment or suggestion welcome. Please contact me before using this class in - * your projects. Referencing this project in your AboutBox/Credits is appreciated. - * - ***********************************************************************************/ - - -#import "NSAttributedString+Attributes.h" - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: NS(Mutable)AttributedString Additions -///////////////////////////////////////////////////////////////////////////// - -@implementation NSAttributedString (OHCommodityConstructors) -+(id)attributedStringWithString:(NSString*)string { - return string ? [[[self alloc] initWithString:string] autorelease] : nil; -} -+(id)attributedStringWithAttributedString:(NSAttributedString*)attrStr { - return attrStr ? [[[self alloc] initWithAttributedString:attrStr] autorelease] : nil; -} - --(CGSize)sizeConstrainedToSize:(CGSize)maxSize { - return [self sizeConstrainedToSize:maxSize fitRange:NULL]; -} --(CGSize)sizeConstrainedToSize:(CGSize)maxSize fitRange:(NSRange*)fitRange { - CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)self); - CFRange fitCFRange = CFRangeMake(0,0); - CGSize sz = CTFramesetterSuggestFrameSizeWithConstraints(framesetter,CFRangeMake(0,0),NULL,maxSize,&fitCFRange); - if (framesetter) CFRelease(framesetter); - if (fitRange) *fitRange = NSMakeRange(fitCFRange.location, fitCFRange.length); - return CGSizeMake( floorf(sz.width+1) , floorf(sz.height+1) ); // take 1pt of margin for security -} -@end - - - - -@implementation NSMutableAttributedString (OHCommodityStyleModifiers) - --(void)setFont:(UIFont*)font { - [self setFontName:font.fontName size:font.pointSize]; -} --(void)setFont:(UIFont*)font range:(NSRange)range { - [self setFontName:font.fontName size:font.pointSize range:range]; -} --(void)setFontName:(NSString*)fontName size:(CGFloat)size { - [self setFontName:fontName size:size range:NSMakeRange(0,[self length])]; -} --(void)setFontName:(NSString*)fontName size:(CGFloat)size range:(NSRange)range { - // kCTFontAttributeName - CTFontRef aFont = CTFontCreateWithName((CFStringRef)fontName, size, NULL); - if (!aFont) return; - [self removeAttribute:(NSString*)kCTFontAttributeName range:range]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTFontAttributeName value:(id)aFont range:range]; - CFRelease(aFont); -} --(void)setFontFamily:(NSString*)fontFamily size:(CGFloat)size bold:(BOOL)isBold italic:(BOOL)isItalic range:(NSRange)range { - // kCTFontFamilyNameAttribute + kCTFontTraitsAttribute - CTFontSymbolicTraits symTrait = (isBold?kCTFontBoldTrait:0) | (isItalic?kCTFontItalicTrait:0); - NSDictionary* trait = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:symTrait] forKey:(NSString*)kCTFontSymbolicTrait]; - NSDictionary* attr = [NSDictionary dictionaryWithObjectsAndKeys: - fontFamily,kCTFontFamilyNameAttribute, - trait,kCTFontTraitsAttribute,nil]; - - CTFontDescriptorRef desc = CTFontDescriptorCreateWithAttributes((CFDictionaryRef)attr); - if (!desc) return; - CTFontRef aFont = CTFontCreateWithFontDescriptor(desc, size, NULL); - CFRelease(desc); - if (!aFont) return; - - [self removeAttribute:(NSString*)kCTFontAttributeName range:range]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTFontAttributeName value:(id)aFont range:range]; - CFRelease(aFont); -} - --(void)setTextColor:(UIColor*)color { - [self setTextColor:color range:NSMakeRange(0,[self length])]; -} --(void)setTextColor:(UIColor*)color range:(NSRange)range { - // kCTForegroundColorAttributeName - [self removeAttribute:(NSString*)kCTForegroundColorAttributeName range:range]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTForegroundColorAttributeName value:(id)color.CGColor range:range]; -} - --(void)setTextIsUnderlined:(BOOL)underlined { - [self setTextIsUnderlined:underlined range:NSMakeRange(0,[self length])]; -} --(void)setTextIsUnderlined:(BOOL)underlined range:(NSRange)range { - int32_t style = underlined ? (kCTUnderlineStyleSingle|kCTUnderlinePatternSolid) : kCTUnderlineStyleNone; - [self setTextUnderlineStyle:style range:range]; -} --(void)setTextUnderlineStyle:(int32_t)style range:(NSRange)range { - [self removeAttribute:(NSString*)kCTUnderlineStyleAttributeName range:range]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTUnderlineStyleAttributeName value:[NSNumber numberWithInt:style] range:range]; -} - --(void)setTextBold:(BOOL)isBold range:(NSRange)range { - NSUInteger startPoint = range.location; - NSRange effectiveRange; - do { - // Get font at startPoint - CTFontRef currentFont = (CTFontRef)[self attribute:(NSString*)kCTFontAttributeName atIndex:startPoint effectiveRange:&effectiveRange]; - // The range for which this font is effective - NSRange fontRange = NSIntersectionRange(range, effectiveRange); - // Create bold/unbold font variant for this font and apply - CTFontRef newFont = CTFontCreateCopyWithSymbolicTraits(currentFont, 0.0, NULL, (isBold?kCTFontBoldTrait:0), kCTFontBoldTrait); - if (newFont) { - [self removeAttribute:(NSString*)kCTFontAttributeName range:fontRange]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTFontAttributeName value:(id)newFont range:fontRange]; - CFRelease(newFont); - } else { - NSString* fontName = [(NSString*)CTFontCopyFullName(currentFont) autorelease]; - NSLog(@"[OHAttributedLabel] Warning: can't find a bold font variant for font %@. Try another font family (like Helvetica) instead.",fontName); - } - ////[self removeAttribute:(NSString*)kCTFontWeightTrait range:fontRange]; // Work around for Apple leak - ////[self addAttribute:(NSString*)kCTFontWeightTrait value:(id)[NSNumber numberWithInt:1.0f] range:fontRange]; - - // If the fontRange was not covering the whole range, continue with next run - startPoint = NSMaxRange(effectiveRange); - } while(startPoint kCTParagraphStyleSpecifierAlignment - CTParagraphStyleSetting paraStyles[2] = { - {.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void*)&alignment}, - {.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void*)&lineBreakMode}, - }; - CTParagraphStyleRef aStyle = CTParagraphStyleCreate(paraStyles, 2); - [self removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)aStyle range:range]; - CFRelease(aStyle); -} - --(void)setTextAlignment:(CTTextAlignment)alignment lineBreakMode:(CTLineBreakMode)lineBreakMode range:(NSRange)range lineHeight:(CGFloat)lineHeight{ - - CTParagraphStyleSetting paraStyles[3] = { - {.spec = kCTParagraphStyleSpecifierAlignment, .valueSize = sizeof(CTTextAlignment), .value = (const void*)&alignment}, - {.spec = kCTParagraphStyleSpecifierLineBreakMode, .valueSize = sizeof(CTLineBreakMode), .value = (const void*)&lineBreakMode}, - {.spec = kCTParagraphStyleSpecifierLineSpacing, .valueSize = sizeof(lineHeight),.value =(const void*)&lineHeight}, - }; - CTParagraphStyleRef aStyle = CTParagraphStyleCreate(paraStyles, 3); - [self removeAttribute:(NSString*)kCTParagraphStyleAttributeName range:range]; // Work around for Apple leak - [self addAttribute:(NSString*)kCTParagraphStyleAttributeName value:(id)aStyle range:range]; - CFRelease(aStyle); -} - -@end - - diff --git a/clients/ios/NewsBlur.xcodeproj/project.pbxproj b/clients/ios/NewsBlur.xcodeproj/project.pbxproj index 60cc02a18..6e7a2eff6 100755 --- a/clients/ios/NewsBlur.xcodeproj/project.pbxproj +++ b/clients/ios/NewsBlur.xcodeproj/project.pbxproj @@ -163,8 +163,6 @@ 43E8382315BC73EB000553BE /* FirstTimeUserAddSitesViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 43E8381D15BC73EB000553BE /* FirstTimeUserAddSitesViewController.xib */; }; 43F44B1C159D8DBC00F48F8A /* FeedTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43F44B1B159D8D7200F48F8A /* FeedTableCell.m */; }; 43F6A79D15B0CDC60092EE91 /* ActivityCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43F6A79C15B0CDC60092EE91 /* ActivityCell.m */; }; - 43F6A7A615B0E1A40092EE91 /* NSAttributedString+Attributes.m in Sources */ = {isa = PBXBuildFile; fileRef = 43F6A7A315B0E1A40092EE91 /* NSAttributedString+Attributes.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; - 43F6A7A715B0E1A40092EE91 /* OHAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = 43F6A7A515B0E1A40092EE91 /* OHAttributedLabel.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 43F6A7A915B0E1ED0092EE91 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F6A7A815B0E1ED0092EE91 /* CoreText.framework */; }; 78095E34128EF30C00230C8E /* ASIAuthenticationDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E25128EF30C00230C8E /* ASIAuthenticationDialog.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; 78095E35128EF30D00230C8E /* ASIDownloadCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E28128EF30C00230C8E /* ASIDownloadCache.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; @@ -660,10 +658,6 @@ 43F44B1B159D8D7200F48F8A /* FeedTableCell.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FeedTableCell.m; sourceTree = ""; }; 43F6A79B15B0CDC60092EE91 /* ActivityCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActivityCell.h; sourceTree = ""; }; 43F6A79C15B0CDC60092EE91 /* ActivityCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ActivityCell.m; sourceTree = ""; }; - 43F6A7A215B0E1A40092EE91 /* NSAttributedString+Attributes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSAttributedString+Attributes.h"; sourceTree = ""; }; - 43F6A7A315B0E1A40092EE91 /* NSAttributedString+Attributes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSAttributedString+Attributes.m"; sourceTree = ""; }; - 43F6A7A415B0E1A40092EE91 /* OHAttributedLabel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OHAttributedLabel.h; sourceTree = ""; }; - 43F6A7A515B0E1A40092EE91 /* OHAttributedLabel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OHAttributedLabel.m; sourceTree = ""; }; 43F6A7A815B0E1ED0092EE91 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; }; 78095E24128EF30C00230C8E /* ASIAuthenticationDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIAuthenticationDialog.h; sourceTree = ""; }; 78095E25128EF30C00230C8E /* ASIAuthenticationDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIAuthenticationDialog.m; sourceTree = ""; }; @@ -1154,10 +1148,6 @@ FF22FE5316E53ADC0046165A /* Underscore */, 43A4BABE15C8663600F3B8D4 /* Popover */, 43A3912E15B73A7B0074B212 /* AFNetworking */, - 43F6A7A215B0E1A40092EE91 /* NSAttributedString+Attributes.h */, - 43F6A7A315B0E1A40092EE91 /* NSAttributedString+Attributes.m */, - 43F6A7A415B0E1A40092EE91 /* OHAttributedLabel.h */, - 43F6A7A515B0E1A40092EE91 /* OHAttributedLabel.m */, FFFC60821716578E00DC22E2 /* THCircularProgressView.h */, FFFC60831716578E00DC22E2 /* THCircularProgressView.m */, 43A4C3E615B0099B008787B5 /* NewsBlur_Prefix.pch */, @@ -2520,8 +2510,6 @@ 43A4C3E415B00966008787B5 /* TransparentToolbar.m in Sources */, 43A4C3E515B00966008787B5 /* UIView+TKCategory.m in Sources */, 43F6A79D15B0CDC60092EE91 /* ActivityCell.m in Sources */, - 43F6A7A615B0E1A40092EE91 /* NSAttributedString+Attributes.m in Sources */, - 43F6A7A715B0E1A40092EE91 /* OHAttributedLabel.m in Sources */, 43ABBCAA15B53A1400EA3111 /* InteractionCell.m in Sources */, 43A3914415B73A7B0074B212 /* AFHTTPClient.m in Sources */, 43A3914515B73A7B0074B212 /* AFHTTPRequestOperation.m in Sources */, @@ -2652,8 +2640,8 @@ ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = Entitlements.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution: NewsBlur, Inc."; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: NewsBlur, Inc."; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; @@ -2676,8 +2664,8 @@ "-all_load", ); PRODUCT_NAME = NewsBlur; - PROVISIONING_PROFILE = "A0156932-124B-4F8E-8B93-EE6598D778F0"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "A0156932-124B-4F8E-8B93-EE6598D778F0"; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; TARGETED_DEVICE_FAMILY = "1,2"; VALID_ARCHS = armv7; "WARNING_CFLAGS[arch=*]" = "-Wall"; @@ -2691,8 +2679,8 @@ ARCHS = "$(ARCHS_STANDARD_32_BIT)"; CLANG_ENABLE_OBJC_ARC = YES; CODE_SIGN_ENTITLEMENTS = Entitlements.entitlements; - CODE_SIGN_IDENTITY = "iPhone Distribution: NewsBlur, Inc."; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution: NewsBlur, Inc."; + CODE_SIGN_IDENTITY = "iPhone Developer"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = YES; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = NewsBlur_Prefix.pch; @@ -2712,8 +2700,8 @@ "-all_load", ); PRODUCT_NAME = NewsBlur; - PROVISIONING_PROFILE = "A0156932-124B-4F8E-8B93-EE6598D778F0"; - "PROVISIONING_PROFILE[sdk=iphoneos*]" = "A0156932-124B-4F8E-8B93-EE6598D778F0"; + PROVISIONING_PROFILE = ""; + "PROVISIONING_PROFILE[sdk=iphoneos*]" = ""; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VALID_ARCHS = armv7; diff --git a/clients/ios/OHAttributedLabel.h b/clients/ios/OHAttributedLabel.h deleted file mode 100755 index 8c064f714..000000000 --- a/clients/ios/OHAttributedLabel.h +++ /dev/null @@ -1,85 +0,0 @@ -/*********************************************************************************** - * - * Copyright (c) 2010 Olivier Halligon - * - * 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. - * - *********************************************************************************** - * - * Created by Olivier Halligon (AliSoftware) on 20 Jul. 2010. - * - * Any comment or suggestion welcome. Please contact me before using this class in - * your projects. Referencing this project in your AboutBox/Credits is appreciated. - * - ***********************************************************************************/ - - -#import -#import - - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: Utility Functions -///////////////////////////////////////////////////////////////////////////// - -CTTextAlignment CTTextAlignmentFromUITextAlignment(UITextAlignment alignment); -CTLineBreakMode CTLineBreakModeFromUILineBreakMode(UILineBreakMode lineBreakMode); - -///////////////////////////////////////////////////////////////////////////// - -@class OHAttributedLabel; -@protocol OHAttributedLabelDelegate -@optional --(BOOL)attributedLabel:(OHAttributedLabel*)attributedLabel shouldFollowLink:(NSTextCheckingResult*)linkInfo; --(UIColor*)colorForLink:(NSTextCheckingResult*)linkInfo underlineStyle:(int32_t*)underlineStyle; //!< Combination of CTUnderlineStyle and CTUnderlineStyleModifiers -@end - -#define UITextAlignmentJustify ((UITextAlignment)kCTJustifiedTextAlignment) - -///////////////////////////////////////////////////////////////////////////// - -@interface OHAttributedLabel : UILabel { - NSMutableAttributedString* _attributedText; //!< Internally mutable, but externally immutable copy access only - CTFrameRef textFrame; - CGRect drawingRect; - NSMutableArray* customLinks; - NSTextCheckingResult* activeLink; - CGPoint touchStartPoint; -} - -/* Attributed String accessors */ -@property(nonatomic, copy) NSAttributedString* attributedText; //!< Use this instead of the "text" property inherited from UILabel to set and get text --(void)resetAttributedText; //!< rebuild the attributedString based on UILabel's text/font/color/alignment/... properties - -/* Links configuration */ -@property(nonatomic, assign) NSTextCheckingTypes automaticallyAddLinksForType; //!< Defaults to NSTextCheckingTypeLink, + NSTextCheckingTypePhoneNumber if "tel:" scheme supported -@property(nonatomic, retain) UIColor* linkColor; //!< Defaults to [UIColor blueColor]. See also OHAttributedLabelDelegate -@property(nonatomic, retain) UIColor* highlightedLinkColor; //[UIColor colorWithWhite:0.2 alpha:0.5] -@property(nonatomic, assign) BOOL underlineLinks; //!< Defaults to YES. See also OHAttributedLabelDelegate --(void)addCustomLink:(NSURL*)linkUrl inRange:(NSRange)range; --(void)removeAllCustomLinks; - -@property(nonatomic, assign) BOOL onlyCatchTouchesOnLinks; //!< If YES, pointInside will only return YES if the touch is on a link. If NO, pointInside will always return YES (Defaults to NO) -@property(nonatomic, assign) IBOutlet id delegate; - -@property(nonatomic, assign) BOOL centerVertically; -@property(nonatomic, assign) BOOL extendBottomToFit; //!< Allows to draw text past the bottom of the view if need. May help in rare cases (like using Emoji) -@end diff --git a/clients/ios/OHAttributedLabel.m b/clients/ios/OHAttributedLabel.m deleted file mode 100644 index ba119d604..000000000 --- a/clients/ios/OHAttributedLabel.m +++ /dev/null @@ -1,659 +0,0 @@ -/*********************************************************************************** - * - * Copyright (c) 2010 Olivier Halligon - * - * 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. - * - *********************************************************************************** - * - * Created by Olivier Halligon (AliSoftware) on 20 Jul. 2010. - * - * Any comment or suggestion welcome. Please contact me before using this class in - * your projects. Referencing this project in your AboutBox/Credits is appreciated. - * - ***********************************************************************************/ - - -#import "OHAttributedLabel.h" -#import "NSAttributedString+Attributes.h" - -#define OHAttributedLabel_WarnAboutKnownIssues 1 - -///////////////////////////////////////////////////////////////////////////// -// MARK: Private Utility methods - -CGPoint CGPointFlipped(CGPoint point, CGRect bounds); -CGRect CGRectFlipped(CGRect rect, CGRect bounds); -NSRange NSRangeFromCFRange(CFRange range); -CGRect CTLineGetTypographicBoundsAsRect(CTLineRef line, CGPoint lineOrigin); -CGRect CTRunGetTypographicBoundsAsRect(CTRunRef run, CTLineRef line, CGPoint lineOrigin); -BOOL CTLineContainsCharactersFromStringRange(CTLineRef line, NSRange range); -BOOL CTRunContainsCharactersFromStringRange(CTRunRef run, NSRange range); - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -///////////////////////////////////////////////////////////////////////////// - - -CTTextAlignment CTTextAlignmentFromUITextAlignment(UITextAlignment alignment) { - switch (alignment) { - case NSTextAlignmentLeft: return kCTLeftTextAlignment; - case UITextAlignmentCenter: return kCTCenterTextAlignment; - case UITextAlignmentRight: return kCTRightTextAlignment; - case UITextAlignmentJustify: return kCTJustifiedTextAlignment; /* special OOB value if we decide to use it even if it's not really standard... */ - default: return kCTNaturalTextAlignment; - } -} - -CTLineBreakMode CTLineBreakModeFromUILineBreakMode(UILineBreakMode lineBreakMode) { - switch (lineBreakMode) { - case UILineBreakModeWordWrap: return kCTLineBreakByWordWrapping; - case UILineBreakModeCharacterWrap: return kCTLineBreakByCharWrapping; - case UILineBreakModeClip: return kCTLineBreakByClipping; - case UILineBreakModeHeadTruncation: return kCTLineBreakByTruncatingHead; - case NSLineBreakByTruncatingTail: return kCTLineBreakByTruncatingTail; - case UILineBreakModeMiddleTruncation: return kCTLineBreakByTruncatingMiddle; - default: return 0; - } -} - -// Don't use this method for origins. Origins always depend on the height of the rect. -CGPoint CGPointFlipped(CGPoint point, CGRect bounds) { - return CGPointMake(point.x, CGRectGetMaxY(bounds)-point.y); -} - -CGRect CGRectFlipped(CGRect rect, CGRect bounds) { - return CGRectMake(CGRectGetMinX(rect), - CGRectGetMaxY(bounds)-CGRectGetMaxY(rect), - CGRectGetWidth(rect), - CGRectGetHeight(rect)); -} - -NSRange NSRangeFromCFRange(CFRange range) { - return NSMakeRange(range.location, range.length); -} - -// Font Metrics: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/FontHandling/Tasks/GettingFontMetrics.html -CGRect CTLineGetTypographicBoundsAsRect(CTLineRef line, CGPoint lineOrigin) { - CGFloat ascent = 0; - CGFloat descent = 0; - CGFloat leading = 0; - CGFloat width = CTLineGetTypographicBounds(line, &ascent, &descent, &leading); - CGFloat height = ascent + descent /* + leading */; - - return CGRectMake(lineOrigin.x, - lineOrigin.y - descent, - width, - height); -} - -CGRect CTRunGetTypographicBoundsAsRect(CTRunRef run, CTLineRef line, CGPoint lineOrigin) { - CGFloat ascent = 0; - CGFloat descent = 0; - CGFloat leading = 0; - CGFloat width = CTRunGetTypographicBounds(run, CFRangeMake(0, 0), &ascent, &descent, &leading); - CGFloat height = ascent + descent /* + leading */; - - CGFloat xOffset = CTLineGetOffsetForStringIndex(line, CTRunGetStringRange(run).location, NULL); - - return CGRectMake(lineOrigin.x + xOffset, - lineOrigin.y - descent, - width, - height); -} - -BOOL CTLineContainsCharactersFromStringRange(CTLineRef line, NSRange range) { - NSRange lineRange = NSRangeFromCFRange(CTLineGetStringRange(line)); - NSRange intersectedRange = NSIntersectionRange(lineRange, range); - return (intersectedRange.length > 0); -} - -BOOL CTRunContainsCharactersFromStringRange(CTRunRef run, NSRange range) { - NSRange runRange = NSRangeFromCFRange(CTRunGetStringRange(run)); - NSRange intersectedRange = NSIntersectionRange(runRange, range); - return (intersectedRange.length > 0); -} - - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: Private interface -///////////////////////////////////////////////////////////////////////////// - - -@interface OHAttributedLabel(/* Private */) --(NSTextCheckingResult*)linkAtCharacterIndex:(CFIndex)idx; --(NSTextCheckingResult*)linkAtPoint:(CGPoint)pt; --(NSMutableAttributedString*)attributedTextWithLinks; --(void)resetTextFrame; --(void)drawActiveLinkHighlightForRect:(CGRect)rect; -#if OHAttributedLabel_WarnAboutKnownIssues --(void)warnAboutKnownIssues_CheckLineBreakMode; --(void)warnAboutKnownIssues_CheckAdjustsFontSizeToFitWidth; -#endif -@end - - - - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: Implementation -///////////////////////////////////////////////////////////////////////////// - - -@implementation OHAttributedLabel - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: Init/Dealloc -///////////////////////////////////////////////////////////////////////////// - -- (void)commonInit -{ - customLinks = [[NSMutableArray alloc] init]; - self.linkColor = [UIColor blueColor]; - self.highlightedLinkColor = [UIColor colorWithWhite:0.4 alpha:0.3]; - self.underlineLinks = YES; - self.automaticallyAddLinksForType = NSTextCheckingTypeLink; - if ([[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"tel:0"]]) { - self.automaticallyAddLinksForType |= NSTextCheckingTypePhoneNumber; - } - self.onlyCatchTouchesOnLinks = YES; - self.userInteractionEnabled = YES; - self.contentMode = UIViewContentModeRedraw; - [self resetAttributedText]; -} - -- (id) initWithFrame:(CGRect)aFrame -{ - self = [super initWithFrame:aFrame]; - if (self != nil) { - [self commonInit]; - } - return self; -} - -- (id)initWithCoder:(NSCoder *)decoder -{ - self = [super initWithCoder:decoder]; - if (self != nil) { - [self commonInit]; -#if OHAttributedLabel_WarnAboutKnownIssues - [self warnAboutKnownIssues_CheckLineBreakMode]; - [self warnAboutKnownIssues_CheckAdjustsFontSizeToFitWidth]; -#endif - } - return self; -} - --(void)dealloc -{ - [_attributedText release]; - [self resetTextFrame]; - - [customLinks release]; - self.linkColor = nil; - self.highlightedLinkColor = nil; - [activeLink release]; - - [super dealloc]; -} - - - -///////////////////////////////////////////////////////////////////////////// -// MARK: - -// MARK: Links Mgmt -///////////////////////////////////////////////////////////////////////////// - --(void)addCustomLink:(NSURL*)linkUrl inRange:(NSRange)range { - NSTextCheckingResult* link = [NSTextCheckingResult linkCheckingResultWithRange:range URL:linkUrl]; - [customLinks addObject:link]; - [self setNeedsDisplay]; -} --(void)removeAllCustomLinks { - [customLinks removeAllObjects]; - [self setNeedsDisplay]; -} - --(NSMutableAttributedString*)attributedTextWithLinks { - NSMutableAttributedString* str = [self.attributedText mutableCopy]; - if (!str) return nil; - - NSString* plainText = [str string]; - if (plainText && (self.automaticallyAddLinksForType > 0)) { - NSError* error = nil; - NSDataDetector* linkDetector = [NSDataDetector dataDetectorWithTypes:self.automaticallyAddLinksForType error:&error]; - [linkDetector enumerateMatchesInString:plainText options:0 range:NSMakeRange(0,[plainText length]) - usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) - { - int32_t uStyle = self.underlineLinks ? kCTUnderlineStyleSingle : kCTUnderlineStyleNone; - UIColor* thisLinkColor = (self.delegate && [self.delegate respondsToSelector:@selector(colorForLink:underlineStyle:)]) - ? [self.delegate colorForLink:result underlineStyle:&uStyle] : self.linkColor; - - if (thisLinkColor) - [str setTextColor:thisLinkColor range:[result range]]; - if (uStyle>0) - [str setTextUnderlineStyle:uStyle range:[result range]]; - }]; - } - [customLinks enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) - { - NSTextCheckingResult* result = (NSTextCheckingResult*)obj; - - int32_t uStyle = self.underlineLinks ? kCTUnderlineStyleSingle : kCTUnderlineStyleNone; - UIColor* thisLinkColor = (self.delegate && [self.delegate respondsToSelector:@selector(colorForLink:underlineStyle:)]) - ? [self.delegate colorForLink:result underlineStyle:&uStyle] : self.linkColor; - - @try { - if (thisLinkColor) - [str setTextColor:thisLinkColor range:[result range]]; - if (uStyle>0) - [str setTextUnderlineStyle:uStyle range:[result range]]; - } - @catch (NSException * e) { - // Protection against NSRangeException - if ([[e name] isEqualToString:NSRangeException]) { - NSLog(@"[OHAttributedLabel] exception: %@",e); - } else { - @throw; - } - } - }]; - return [str autorelease]; -} - --(NSTextCheckingResult*)linkAtCharacterIndex:(CFIndex)idx { - __block NSTextCheckingResult* foundResult = nil; - - NSString* plainText = [_attributedText string]; - if (plainText && (self.automaticallyAddLinksForType > 0)) { - NSError* error = nil; - NSDataDetector* linkDetector = [NSDataDetector dataDetectorWithTypes:self.automaticallyAddLinksForType error:&error]; - [linkDetector enumerateMatchesInString:plainText options:0 range:NSMakeRange(0,[plainText length]) - usingBlock:^(NSTextCheckingResult *result, NSMatchingFlags flags, BOOL *stop) - { - NSRange r = [result range]; - if (NSLocationInRange(idx, r)) { - foundResult = [[result retain] autorelease]; - *stop = YES; - } - }]; - if (foundResult) return foundResult; - } - - [customLinks enumerateObjectsUsingBlock:^(id obj, NSUInteger aidx, BOOL *stop) - { - NSRange r = [(NSTextCheckingResult*)obj range]; - if (NSLocationInRange(idx, r)) { - foundResult = [[obj retain] autorelease]; - *stop = YES; - } - }]; - return foundResult; -} - --(NSTextCheckingResult*)linkAtPoint:(CGPoint)point { - static const CGFloat kVMargin = 5.f; - if (!CGRectContainsPoint(CGRectInset(drawingRect, 0, -kVMargin), point)) return nil; - - CFArrayRef lines = CTFrameGetLines(textFrame); - if (!lines) return nil; - CFIndex nbLines = CFArrayGetCount(lines); - NSTextCheckingResult* link = nil; - - CGPoint origins[nbLines]; - CTFrameGetLineOrigins(textFrame, CFRangeMake(0,0), origins); - - for (int lineIndex=0 ; lineIndex