2010-06-21 17:17:26 -04:00
//
// FeedDetailViewController . m
// NewsBlur
//
// Created by Samuel Clay on 6 / 20 / 10.
// Copyright 2010 NewsBlur . All rights reserved .
//
2011-10-26 08:40:31 -07:00
# import < QuartzCore / QuartzCore . h >
2010-06-21 17:17:26 -04:00
# import "FeedDetailViewController.h"
# import "NewsBlurAppDelegate.h"
2012-07-25 17:29:29 -07:00
# import "NBContainerViewController.h"
2010-07-15 00:44:38 -04:00
# import "FeedDetailTableCell.h"
2011-07-24 22:23:38 -07:00
# import "ASIFormDataRequest.h"
2012-07-12 22:05:23 -07:00
# import "UserProfileViewController.h"
2012-08-02 18:00:48 -07:00
# import "StoryDetailViewController.h"
2012-11-06 17:26:08 -08:00
# import "StoryPageControl.h"
2011-08-08 09:58:15 -07:00
# import "NSString+HTML.h"
2011-10-17 09:28:15 -07:00
# import "MBProgressHUD.h"
2011-09-05 22:06:31 -07:00
# import "Base64.h"
2010-06-24 00:22:26 -04:00
# import "JSON.h"
2011-10-26 08:40:31 -07:00
# import "StringHelper.h"
2011-10-17 09:37:16 -07:00
# import "Utilities.h"
2012-10-12 13:58:26 -04:00
# import "UIBarButtonItem+WEPopover.h"
# import "WEPopoverController.h"
2013-02-27 17:22:49 -08:00
# import "UIBarButtonItem+Image.h"
2013-04-22 17:15:50 -07:00
# import "FeedDetailMenuViewController.h"
2013-06-07 02:47:43 -04:00
# import "NBNotifier.h"
2013-06-12 19:21:56 -07:00
# import "NBLoadingCell.h"
2013-06-14 19:21:30 -07:00
# import "FMDatabase.h"
2013-09-24 17:18:20 -07:00
# import "NBBarButtonItem.h"
2013-10-09 14:54:49 -07:00
# import "UIActivitiesControl.h"
2012-07-25 17:29:29 -07:00
2013-10-17 18:56:14 -07:00
# define kTableViewRowHeight 38 ;
# define kTableViewRiverRowHeight 60 ;
2012-08-10 18:10:07 -07:00
# define kTableViewShortRowDifference 15 ;
2011-11-05 16:25:04 -07:00
# define kMarkReadActionSheet 1 ;
# define kSettingsActionSheet 2 ;
2010-06-21 17:17:26 -04:00
2012-08-08 19:31:33 -07:00
@ interface FeedDetailViewController ( )
@ property ( nonatomic ) UIActionSheet * actionSheet_ ; // add this line
@ end
2010-06-21 17:17:26 -04:00
@ implementation FeedDetailViewController
2012-07-12 22:05:23 -07:00
@ synthesize popoverController ;
2013-02-27 17:22:49 -08:00
@ synthesize storyTitlesTable , feedMarkReadButton ;
@ synthesize settingsBarButton ;
2013-02-27 17:39:54 -08:00
@ synthesize separatorBarButton ;
2013-04-15 10:29:39 -07:00
@ synthesize titleImageBarButton ;
2013-10-11 17:46:09 -07:00
@ synthesize spacerBarButton , spacer2BarButton ;
2010-06-21 17:17:26 -04:00
@ synthesize appDelegate ;
2011-07-20 22:21:11 -07:00
@ synthesize feedPage ;
@ synthesize pageFetching ;
2011-07-24 16:52:24 -07:00
@ synthesize pageFinished ;
2012-08-08 19:31:33 -07:00
@ synthesize actionSheet_ ;
2013-02-21 17:57:32 -08:00
@ synthesize finishedAnimatingIn ;
2013-06-10 00:29:03 -07:00
@ synthesize notifier ;
2013-06-20 20:38:40 -07:00
@ synthesize isOffline ;
2013-08-12 11:59:07 -07:00
@ synthesize isShowingOffline ;
2010-06-21 17:17:26 -04:00
- ( id ) initWithNibName : ( NSString * ) nibNameOrNil bundle : ( NSBundle * ) nibBundleOrNil {
2011-03-09 18:23:55 -05:00
if ( ( self = [ super initWithNibName : nibNameOrNil bundle : nibBundleOrNil ] ) ) {
2010-06-21 17:17:26 -04:00
}
return self ;
}
2012-07-18 17:23:57 -07:00
2011-10-05 10:07:26 -07:00
- ( void ) viewDidLoad {
2012-08-10 18:10:07 -07:00
[ super viewDidLoad ] ;
2013-10-17 18:56:14 -07:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( preferredContentSizeChanged : )
name : UIContentSizeCategoryDidChangeNotification
object : nil ] ;
2012-10-12 13:58:26 -04:00
popoverClass = [ WEPopoverController class ] ;
2012-08-10 18:10:07 -07:00
self . storyTitlesTable . backgroundColor = UIColorFromRGB ( 0 xf4f4f4 ) ;
2013-03-04 17:15:50 -08:00
self . storyTitlesTable . separatorColor = UIColorFromRGB ( 0 xE9E8E4 ) ;
2013-02-27 17:22:49 -08:00
spacerBarButton = [ [ UIBarButtonItem alloc ]
initWithBarButtonSystemItem : UIBarButtonSystemItemFixedSpace target : nil action : nil ] ;
2013-10-11 17:46:09 -07:00
spacerBarButton . width = 0 ;
2013-02-27 17:39:54 -08:00
spacer2BarButton = [ [ UIBarButtonItem alloc ]
2013-10-11 17:46:09 -07:00
initWithBarButtonSystemItem : UIBarButtonSystemItemFixedSpace target : nil action : nil ] ;
spacer2BarButton . width = 0 ;
2013-02-27 17:22:49 -08:00
UIImage * separatorImage = [ UIImage imageNamed : @ "bar-separator.png" ] ;
separatorBarButton = [ UIBarButtonItem barItemWithImage : separatorImage target : nil action : nil ] ;
[ separatorBarButton setEnabled : NO ] ;
UIImage * settingsImage = [ UIImage imageNamed : @ "nav_icn_settings.png" ] ;
settingsBarButton = [ UIBarButtonItem barItemWithImage : settingsImage target : self action : @ selector ( doOpenSettingsActionSheet : ) ] ;
2013-10-11 17:46:09 -07:00
2013-02-27 17:22:49 -08:00
UIImage * markreadImage = [ UIImage imageNamed : @ "markread.png" ] ;
feedMarkReadButton = [ UIBarButtonItem barItemWithImage : markreadImage target : self action : @ selector ( doOpenMarkReadActionSheet : ) ] ;
2013-04-15 10:29:39 -07:00
titleImageBarButton = [ UIBarButtonItem alloc ] ;
2013-06-13 17:56:58 -07:00
2013-10-09 14:54:49 -07:00
UILongPressGestureRecognizer * longpress = [ [ UILongPressGestureRecognizer alloc ]
initWithTarget : self action : @ selector ( handleLongPress : ) ] ;
longpress . minimumPressDuration = 1.0 ;
longpress . delegate = self ;
[ self . storyTitlesTable addGestureRecognizer : longpress ] ;
2013-06-13 17:56:58 -07:00
self . notifier = [ [ NBNotifier alloc ] initWithTitle : @ "Fetching stories..." inView : self . view ] ;
2013-06-19 20:26:04 -07:00
[ self . view addSubview : self . notifier ] ;
2011-08-18 09:56:52 -07:00
}
2013-10-17 18:56:14 -07:00
- ( void ) preferredContentSizeChanged : ( NSNotification * ) aNotification {
[ self . storyTitlesTable reloadData ] ;
}
2012-06-08 10:37:51 -07:00
- ( BOOL ) shouldAutorotateToInterfaceOrientation : ( UIInterfaceOrientation ) interfaceOrientation {
2012-06-08 19:21:10 -07:00
return YES ;
2012-06-08 10:37:51 -07:00
}
2012-06-29 23:25:56 -07:00
2012-07-09 21:26:53 -07:00
- ( void ) willAnimateRotationToInterfaceOrientation : ( UIInterfaceOrientation ) toInterfaceOrientation
duration : ( NSTimeInterval ) duration {
2012-08-02 18:00:48 -07:00
[ self setUserAvatarLayout : toInterfaceOrientation ] ;
2012-06-29 23:25:56 -07:00
}
2012-07-18 17:23:57 -07:00
- ( void ) didRotateFromInterfaceOrientation : ( UIInterfaceOrientation ) fromInterfaceOrientation {
[ self checkScroll ] ;
}
2012-07-15 18:23:08 -07:00
- ( void ) viewWillAppear : ( BOOL ) animated {
2012-08-02 18:00:48 -07:00
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
[ self setUserAvatarLayout : orientation ] ;
2013-02-21 17:57:32 -08:00
self . finishedAnimatingIn = NO ;
2013-10-11 17:46:09 -07:00
[ MBProgressHUD hideHUDForView : self . view animated : NO ] ;
2013-06-11 23:00:00 -07:00
2012-07-12 22:05:23 -07:00
// set right avatar title image
2013-10-11 17:46:09 -07:00
spacerBarButton . width = 0 ;
spacer2BarButton . width = 0 ;
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
spacerBarButton . width = -6 ;
spacer2BarButton . width = 10 ;
}
2012-07-12 22:05:23 -07:00
if ( appDelegate . isSocialView ) {
2013-10-11 17:46:09 -07:00
spacerBarButton . width = -6 ;
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ appDelegate . activeFeed objectForKey : @ "id" ] ] ;
UIImage * titleImage = [ Utilities getImage : feedIdStr isSocial : YES ] ;
titleImage = [ Utilities roundCorneredImage : titleImage radius : 6 ] ;
[ ( ( UIButton * ) titleImageBarButton . customView ) . imageView removeFromSuperview ] ;
titleImageBarButton = [ UIBarButtonItem barItemWithImage : titleImage
target : self
action : @ selector ( showUserProfile ) ] ;
titleImageBarButton . customView . frame = CGRectMake ( 0 , 0 , 32 , 32 ) ;
self . navigationItem . rightBarButtonItems = [ NSArray arrayWithObjects :
spacerBarButton ,
titleImageBarButton ,
spacer2BarButton ,
separatorBarButton ,
feedMarkReadButton , nil ] ;
2012-07-12 22:05:23 -07:00
} else {
2013-10-11 17:46:09 -07:00
self . navigationItem . rightBarButtonItems = [ NSArray arrayWithObjects :
spacerBarButton ,
settingsBarButton ,
spacer2BarButton ,
separatorBarButton ,
feedMarkReadButton ,
nil ] ;
2012-07-12 22:05:23 -07:00
}
2011-07-24 21:47:58 -07:00
2013-10-11 17:46:09 -07:00
// set center title
2013-10-11 18:07:30 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPhone &&
! self . navigationItem . titleView ) {
self . navigationItem . titleView = [ appDelegate makeFeedTitle : appDelegate . activeFeed ] ;
2013-10-11 17:46:09 -07:00
}
2013-10-03 13:54:15 -07:00
2011-07-24 21:47:58 -07:00
NSMutableArray * indexPaths = [ NSMutableArray array ] ;
2013-10-11 17:46:09 -07:00
// NSLog ( @ "appDelegate.recentlyReadStoryLocations: %d - %@" , self . isOffline , appDelegate . recentlyReadStoryLocations ) ;
2013-07-19 12:20:51 -07:00
for ( id i in appDelegate . recentlyReadStoryLocations ) {
2011-07-24 21:47:58 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : [ i intValue ]
2013-04-15 10:29:39 -07:00
inSection : 0 ] ;
2011-08-16 19:55:44 -07:00
// NSLog ( @ "Read story: %d" , [ i intValue ] ) ;
2013-02-14 17:16:47 -08:00
if ( ! [ indexPaths containsObject : indexPath ] ) {
[ indexPaths addObject : indexPath ] ;
}
2011-07-24 21:47:58 -07:00
}
2013-07-19 17:20:39 -07:00
if ( [ indexPaths count ] > 0 && [ self . storyTitlesTable numberOfRowsInSection : 0 ] ) {
2013-09-26 19:26:10 -07:00
// [ self . storyTitlesTable beginUpdates ] ;
// [ self . storyTitlesTable reloadRowsAtIndexPaths : indexPaths withRowAnimation : UITableViewRowAnimationNone ] ;
// [ self . storyTitlesTable endUpdates ] ;
[ self . storyTitlesTable reloadData ] ;
2011-07-24 21:47:58 -07:00
}
2011-10-30 18:53:10 -07:00
2013-07-19 12:20:51 -07:00
appDelegate . recentlyReadStoryLocations = [ NSMutableArray array ] ;
2013-04-26 16:41:25 -07:00
appDelegate . originalStoryCount = [ appDelegate unreadCount ] ;
2012-10-03 16:08:40 -07:00
if ( ( appDelegate . isSocialRiverView ||
appDelegate . isSocialView ||
2012-10-17 15:07:53 -07:00
[ appDelegate . activeFolder isEqualToString : @ "saved_stories" ] ) ) {
2013-02-27 17:22:49 -08:00
settingsBarButton . enabled = NO ;
2011-12-05 10:42:25 -08:00
} else {
2013-02-27 17:22:49 -08:00
settingsBarButton . enabled = YES ;
2012-07-16 19:45:14 -07:00
}
2012-08-08 19:31:33 -07:00
if ( appDelegate . isSocialRiverView ||
2012-10-17 15:07:53 -07:00
[ appDelegate . activeFolder isEqualToString : @ "saved_stories" ] ) {
2012-08-08 19:31:33 -07:00
feedMarkReadButton . enabled = NO ;
} else {
feedMarkReadButton . enabled = YES ;
}
2012-08-07 09:57:21 -07:00
2012-08-06 15:46:05 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPhone ) {
[ self . storyTitlesTable reloadData ] ;
2013-09-25 17:43:00 -07:00
NSInteger location = appDelegate . locationOfActiveStory ;
2012-08-07 09:57:21 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : location inSection : 0 ] ;
2013-02-21 17:57:32 -08:00
if ( indexPath && location >= 0 ) {
2012-11-16 12:02:27 -08:00
[ self . storyTitlesTable selectRowAtIndexPath : indexPath animated : NO scrollPosition : UITableViewScrollPositionMiddle ] ;
}
2012-10-04 15:44:25 -07:00
[ self performSelector : @ selector ( fadeSelectedCell ) withObject : self afterDelay : 0.4 ] ;
2012-08-06 15:46:05 -07:00
}
2013-06-19 20:26:04 -07:00
[ self . notifier setNeedsLayout ] ;
2013-09-23 15:07:25 -07:00
[ appDelegate hideShareView : YES ] ;
2010-06-21 17:17:26 -04:00
}
2012-08-07 09:57:21 -07:00
- ( void ) viewDidAppear : ( BOOL ) animated {
2013-03-01 15:48:18 -08:00
[ super viewDidAppear : animated ] ;
2012-11-06 17:26:08 -08:00
if ( appDelegate . inStoryDetail && UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPhone ) {
2012-08-07 09:57:21 -07:00
appDelegate . inStoryDetail = NO ;
2013-10-16 12:52:21 -07:00
[ appDelegate . storyPageControl resetPages ] ;
2012-08-13 23:35:11 -07:00
[ self checkScroll ] ;
2012-08-07 09:57:21 -07:00
}
2013-02-21 17:57:32 -08:00
self . finishedAnimatingIn = YES ;
[ self testForTryFeed ] ;
2012-08-07 09:57:21 -07:00
}
2013-09-25 10:47:35 -07:00
- ( void ) viewDidDisappear : ( BOOL ) animated {
2012-07-12 22:05:23 -07:00
[ self . popoverController dismissPopoverAnimated : YES ] ;
2012-10-12 13:58:26 -04:00
self . popoverController = nil ;
2012-07-12 22:05:23 -07:00
}
2012-08-06 15:46:05 -07:00
- ( void ) fadeSelectedCell {
// have the selected cell deselect
2013-09-25 17:43:00 -07:00
NSInteger location = appDelegate . locationOfActiveStory ;
2012-07-15 16:46:46 -07:00
2012-08-06 15:46:05 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : location inSection : 0 ] ;
if ( indexPath ) {
[ self . storyTitlesTable deselectRowAtIndexPath : indexPath animated : YES ] ;
}
2010-06-21 17:17:26 -04:00
}
2012-08-02 18:00:48 -07:00
- ( void ) setUserAvatarLayout : ( UIInterfaceOrientation ) orientation {
2013-02-27 17:22:49 -08:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPhone && appDelegate . isSocialView ) {
2012-08-02 18:00:48 -07:00
if ( UIInterfaceOrientationIsPortrait ( orientation ) ) {
2013-09-24 17:18:20 -07:00
NBBarButtonItem * avatar = ( NBBarButtonItem * ) titleImageBarButton . customView ;
2012-08-02 18:00:48 -07:00
CGRect buttonFrame = avatar . frame ;
buttonFrame . size = CGSizeMake ( 32 , 32 ) ;
avatar . frame = buttonFrame ;
} else {
2013-09-24 17:18:20 -07:00
NBBarButtonItem * avatar = ( NBBarButtonItem * ) titleImageBarButton . customView ;
2012-08-02 18:00:48 -07:00
CGRect buttonFrame = avatar . frame ;
buttonFrame . size = CGSizeMake ( 28 , 28 ) ;
avatar . frame = buttonFrame ;
}
}
}
2010-06-21 17:17:26 -04:00
# pragma mark -
2010-06-24 00:22:26 -04:00
# pragma mark Initialization
2011-09-06 17:51:02 -07:00
- ( void ) resetFeedDetail {
2013-07-17 19:22:41 -07:00
appDelegate . hasLoadedFeedDetail = NO ;
2013-10-11 18:07:30 -07:00
self . navigationItem . titleView = nil ;
2011-09-06 17:51:02 -07:00
self . pageFetching = NO ;
self . pageFinished = NO ;
2013-07-31 18:42:18 -07:00
self . isOffline = NO ;
2013-08-12 11:59:07 -07:00
self . isShowingOffline = NO ;
2011-09-06 17:51:02 -07:00
self . feedPage = 1 ;
2012-12-11 12:01:49 -08:00
appDelegate . activeStory = nil ;
2012-11-26 09:54:20 -08:00
[ appDelegate . storyPageControl resetPages ] ;
2013-07-19 15:41:43 -07:00
appDelegate . recentlyReadStories = [ NSMutableDictionary dictionary ] ;
2013-07-19 12:20:51 -07:00
appDelegate . recentlyReadStoryLocations = [ NSMutableArray array ] ;
2013-06-13 17:56:58 -07:00
[ self . notifier hideIn : 0 ] ;
2013-07-17 19:22:41 -07:00
[ self cancelRequests ] ;
2013-06-13 17:56:58 -07:00
[ self beginOfflineTimer ] ;
2011-09-06 17:51:02 -07:00
}
2012-10-30 17:05:39 -07:00
- ( void ) reloadPage {
[ self resetFeedDetail ] ;
[ appDelegate setStories : nil ] ;
appDelegate . storyCount = 0 ;
2012-12-11 11:50:06 -08:00
appDelegate . activeClassifiers = [ NSMutableDictionary dictionary ] ;
2012-12-27 00:15:26 -08:00
appDelegate . activePopularAuthors = [ NSArray array ] ;
appDelegate . activePopularTags = [ NSArray array ] ;
2013-06-26 11:38:49 -07:00
2012-10-30 17:05:39 -07:00
if ( appDelegate . isRiverView ) {
[ self fetchRiverPage : 1 withCallback : nil ] ;
} else {
[ self fetchFeedDetail : 1 withCallback : nil ] ;
}
2013-08-06 18:08:55 -07:00
[ self . storyTitlesTable reloadData ] ;
[ storyTitlesTable scrollRectToVisible : CGRectMake ( 0 , 0 , 1 , 1 ) animated : YES ] ;
2012-10-30 17:05:39 -07:00
}
2013-06-13 17:56:58 -07:00
- ( void ) beginOfflineTimer {
2013-06-17 11:50:13 -07:00
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , 1 * NSEC_PER _SEC ) , dispatch_get _main _queue ( ) , ^ {
2013-10-10 12:58:40 -07:00
if ( ! appDelegate . storyLocationsCount && ! self . pageFinished &&
self . feedPage = = 1 && ! self . isOffline ) {
2013-08-12 11:59:07 -07:00
self . isShowingOffline = YES ;
2013-07-31 18:42:18 -07:00
self . isOffline = YES ;
[ self showLoadingNotifier ] ;
2013-06-13 17:56:58 -07:00
[ self loadOfflineStories ] ;
}
} ) ;
}
2012-06-29 10:20:06 -07:00
# pragma mark -
# pragma mark Regular and Social Feeds
2011-09-05 22:06:31 -07:00
- ( void ) fetchNextPage : ( void ( ^ ) ( ) ) callback {
2012-10-17 18:09:20 -07:00
if ( appDelegate . isRiverView ) {
[ self fetchRiverPage : self . feedPage + 1 withCallback : callback ] ;
} else {
[ self fetchFeedDetail : self . feedPage + 1 withCallback : callback ] ;
}
2011-09-05 22:06:31 -07:00
}
2012-10-17 18:09:20 -07:00
- ( void ) fetchFeedDetail : ( int ) page withCallback : ( void ( ^ ) ( ) ) callback {
2012-06-25 15:02:20 -07:00
NSString * theFeedDetailURL ;
2012-12-20 12:08:35 -08:00
if ( ! appDelegate . activeFeed ) return ;
2012-11-06 17:26:08 -08:00
if ( callback || ( ! self . pageFetching && ! self . pageFinished ) ) {
2012-07-16 19:45:14 -07:00
2011-07-20 22:21:11 -07:00
self . feedPage = page ;
self . pageFetching = YES ;
2013-09-25 17:43:00 -07:00
NSInteger storyCount = appDelegate . storyCount ;
2011-07-24 16:52:24 -07:00
if ( storyCount = = 0 ) {
[ self . storyTitlesTable reloadData ] ;
2011-07-22 09:10:13 -07:00
[ storyTitlesTable scrollRectToVisible : CGRectMake ( 0 , 0 , 1 , 1 ) animated : YES ] ;
}
2013-06-26 16:22:44 -07:00
if ( self . feedPage = = 1 ) {
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
[ appDelegate . database inDatabase : ^ ( FMDatabase * db ) {
[ appDelegate prepareActiveCachedImages : db ] ;
} ] ;
} ) ;
}
2013-07-31 18:42:18 -07:00
if ( self . isOffline ) {
[ self loadOfflineStories ] ;
2013-08-12 11:59:07 -07:00
if ( ! self . isShowingOffline ) {
[ self showOfflineNotifier ] ;
}
2013-07-31 18:42:18 -07:00
return ;
}
2012-06-26 16:24:19 -07:00
if ( appDelegate . isSocialView ) {
2013-06-18 21:23:20 -04:00
theFeedDetailURL = [ NSString stringWithFormat : @ "%@/social/stories/%@/?page=%d" ,
2012-06-25 15:02:20 -07:00
NEWSBLUR_URL ,
[ appDelegate . activeFeed objectForKey : @ "user_id" ] ,
self . feedPage ] ;
} else {
2013-06-18 21:23:20 -04:00
theFeedDetailURL = [ NSString stringWithFormat : @ "%@/reader/feed/%@/?page=%d" ,
2012-06-25 15:02:20 -07:00
NEWSBLUR_URL ,
[ appDelegate . activeFeed objectForKey : @ "id" ] ,
self . feedPage ] ;
}
2012-10-30 17:05:39 -07:00
2013-06-21 18:35:06 -07:00
theFeedDetailURL = [ NSString stringWithFormat : @ "%@&order=%@" ,
theFeedDetailURL ,
[ appDelegate activeOrder ] ] ;
theFeedDetailURL = [ NSString stringWithFormat : @ "%@&read_filter=%@" ,
theFeedDetailURL ,
[ appDelegate activeReadFilter ] ] ;
2012-10-30 17:05:39 -07:00
2011-11-30 09:38:31 -08:00
[ self cancelRequests ] ;
2012-07-15 15:06:06 -07:00
__weak ASIHTTPRequest * request = [ self requestWithURL : theFeedDetailURL ] ;
2011-09-05 22:06:31 -07:00
[ request setDelegate : self ] ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setFailedBlock : ^ ( void ) {
2012-07-12 00:10:42 -07:00
NSLog ( @ "in failed block %@" , request ) ;
2013-07-17 19:00:00 -07:00
if ( request . isCancelled ) {
NSLog ( @ "Cancelled" ) ;
return ;
2013-10-10 12:58:40 -07:00
} else {
2013-06-20 20:38:40 -07:00
self . isOffline = YES ;
2013-10-10 12:58:40 -07:00
self . feedPage = 1 ;
2013-06-13 21:56:13 -07:00
[ self loadOfflineStories ] ;
[ self showOfflineNotifier ] ;
}
2013-06-20 20:38:40 -07:00
[ self . storyTitlesTable reloadData ] ;
2011-09-05 22:06:31 -07:00
} ] ;
[ request setCompletionBlock : ^ ( void ) {
2012-12-20 12:08:35 -08:00
if ( ! appDelegate . activeFeed ) return ;
2011-09-05 22:06:31 -07:00
[ self finishedLoadingFeed : request ] ;
if ( callback ) {
callback ( ) ;
}
} ] ;
2013-06-10 00:29:03 -07:00
[ request setTimeOutSeconds : 30 ] ;
2011-09-05 22:06:31 -07:00
[ request setTag : [ [ [ appDelegate activeFeed ] objectForKey : @ "id" ] intValue ] ] ;
[ request startAsynchronous ] ;
2013-07-17 19:00:00 -07:00
[ requests addObject : request ] ;
2011-09-05 22:06:31 -07:00
}
2010-07-15 23:32:37 -04:00
}
2013-06-13 17:56:58 -07:00
- ( void ) loadOfflineStories {
2013-07-31 18:42:18 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
2013-06-14 19:21:30 -07:00
[ appDelegate . database inDatabase : ^ ( FMDatabase * db ) {
2013-06-14 19:44:57 -07:00
NSArray * feedIds ;
2013-09-25 17:43:00 -07:00
NSInteger limit = 12 ;
NSInteger offset = ( self . feedPage - 1 ) * limit ;
2013-06-20 21:46:09 -07:00
2013-06-14 19:44:57 -07:00
if ( appDelegate . isRiverView ) {
feedIds = appDelegate . activeFolderFeeds ;
2013-06-20 20:38:40 -07:00
} else if ( appDelegate . activeFeed ) {
2013-06-14 19:44:57 -07:00
feedIds = @ [ [ appDelegate . activeFeed objectForKey : @ "id" ] ] ;
2013-06-20 20:38:40 -07:00
} else {
return ;
2013-06-14 19:44:57 -07:00
}
2013-06-15 08:56:43 -07:00
2013-06-21 18:35:06 -07:00
NSString * orderSql ;
if ( [ appDelegate . activeOrder isEqualToString : @ "oldest" ] ) {
orderSql = @ "ASC" ;
2013-06-15 08:56:43 -07:00
} else {
2013-06-21 18:35:06 -07:00
orderSql = @ "DESC" ;
2013-06-15 08:56:43 -07:00
}
2013-06-21 18:35:06 -07:00
NSString * readFilterSql ;
if ( [ appDelegate . activeReadFilter isEqualToString : @ "unread" ] ) {
readFilterSql = @ "INNER JOIN unread_hashes uh ON s.story_hash = uh.story_hash" ;
2013-06-15 08:56:43 -07:00
} else {
2013-06-21 18:35:06 -07:00
readFilterSql = @ "" ;
2013-06-15 08:56:43 -07:00
}
2013-09-25 17:43:00 -07:00
NSString * sql = [ NSString stringWithFormat : @ "SELECT * FROM stories s %@ WHERE s.story_feed_id IN (%@) ORDER BY s.story_timestamp %@ LIMIT %ld OFFSET %ld" ,
2013-06-21 18:35:06 -07:00
readFilterSql ,
2013-06-15 08:56:43 -07:00
[ feedIds componentsJoinedByString : @ "," ] ,
2013-07-31 18:42:18 -07:00
orderSql ,
2013-09-25 17:43:00 -07:00
( long ) limit , ( long ) offset ] ;
2013-06-14 19:44:57 -07:00
FMResultSet * cursor = [ db executeQuery : sql ] ;
2013-06-14 19:21:30 -07:00
NSMutableArray * offlineStories = [ NSMutableArray array ] ;
while ( [ cursor next ] ) {
NSDictionary * story = [ cursor resultDictionary ] ;
[ offlineStories addObject : [ NSJSONSerialization
JSONObjectWithData : [ [ story objectForKey : @ "story_json" ]
dataUsingEncoding : NSUTF8StringEncoding ]
options : nil error : nil ] ] ;
}
2013-10-03 18:07:39 -07:00
[ cursor close ] ;
2013-06-14 19:21:30 -07:00
2013-06-21 18:35:06 -07:00
if ( [ appDelegate . activeReadFilter isEqualToString : @ "all" ] ) {
2013-06-20 21:46:09 -07:00
NSString * unreadHashSql = [ NSString stringWithFormat : @ "SELECT s.story_hash FROM stories s INNER JOIN unread_hashes uh ON s.story_hash = uh.story_hash WHERE s.story_feed_id IN (%@)" ,
[ feedIds componentsJoinedByString : @ "," ] ] ;
FMResultSet * unreadHashCursor = [ db executeQuery : unreadHashSql ] ;
2013-07-31 18:42:18 -07:00
NSMutableDictionary * unreadStoryHashes ;
if ( self . feedPage = = 1 ) {
unreadStoryHashes = [ NSMutableDictionary dictionary ] ;
} else {
2013-09-05 12:38:06 -07:00
unreadStoryHashes = appDelegate . unreadStoryHashes ;
2013-07-31 18:42:18 -07:00
}
2013-06-20 21:46:09 -07:00
while ( [ unreadHashCursor next ] ) {
[ unreadStoryHashes setObject : [ NSNumber numberWithBool : YES ] forKey : [ unreadHashCursor objectForColumnName : @ "story_hash" ] ] ;
}
2013-09-05 12:38:06 -07:00
appDelegate . unreadStoryHashes = unreadStoryHashes ;
2013-10-03 18:07:39 -07:00
[ unreadHashCursor close ] ;
2013-06-20 21:46:09 -07:00
}
2013-10-17 17:23:52 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2013-07-31 18:42:18 -07:00
if ( ! self . isOffline ) {
NSLog ( @ "Online before offline rendered. Tossing offline stories." ) ;
return ;
}
if ( ! [ offlineStories count ] ) {
self . pageFinished = YES ;
2013-08-06 15:43:37 -07:00
[ self . storyTitlesTable reloadData ] ;
2013-07-31 18:42:18 -07:00
} else {
[ self renderStories : offlineStories ] ;
}
2013-08-12 11:59:07 -07:00
if ( ! self . isShowingOffline ) {
[ self showOfflineNotifier ] ;
}
2013-07-31 18:42:18 -07:00
} ) ;
2013-06-14 19:21:30 -07:00
} ] ;
2013-07-31 18:42:18 -07:00
} ) ;
2013-06-13 17:56:58 -07:00
}
- ( void ) showOfflineNotifier {
2013-07-31 18:42:18 -07:00
// [ self . notifier hide ] ;
2013-06-13 17:56:58 -07:00
self . notifier . style = NBOfflineStyle ;
self . notifier . title = @ "Offline" ;
[ self . notifier show ] ;
}
- ( void ) showLoadingNotifier {
[ self . notifier hide ] ;
self . notifier . style = NBLoadingStyle ;
2013-06-13 21:56:13 -07:00
self . notifier . title = @ "Fetching recent stories..." ;
2013-06-13 17:56:58 -07:00
[ self . notifier show ] ;
}
2012-06-29 10:20:06 -07:00
# pragma mark -
# pragma mark River of News
2013-06-21 22:18:54 -07:00
- ( void ) fetchRiverPage : ( int ) page withCallback : ( void ( ^ ) ( ) ) callback {
2012-06-29 10:20:06 -07:00
if ( ! self . pageFetching && ! self . pageFinished ) {
self . feedPage = page ;
self . pageFetching = YES ;
2013-09-25 17:43:00 -07:00
NSInteger storyCount = appDelegate . storyCount ;
2012-06-29 10:20:06 -07:00
if ( storyCount = = 0 ) {
[ self . storyTitlesTable reloadData ] ;
[ storyTitlesTable scrollRectToVisible : CGRectMake ( 0 , 0 , 1 , 1 ) animated : YES ] ;
2013-06-11 23:00:00 -07:00
// [ self . notifier initWithTitle : @ "Loading more..." inView : self . view ] ;
2013-06-10 00:29:03 -07:00
2012-06-29 10:20:06 -07:00
}
2013-06-26 16:22:44 -07:00
if ( self . feedPage = = 1 ) {
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
[ appDelegate . database inDatabase : ^ ( FMDatabase * db ) {
[ appDelegate prepareActiveCachedImages : db ] ;
} ] ;
} ) ;
}
2013-07-31 18:42:18 -07:00
if ( self . isOffline ) {
[ self loadOfflineStories ] ;
return ;
}
2012-08-08 10:57:38 -07:00
NSString * theFeedDetailURL ;
if ( appDelegate . isSocialRiverView ) {
2012-12-07 15:17:22 -08:00
if ( [ appDelegate . activeFolder isEqualToString : @ "river_global" ] ) {
theFeedDetailURL = [ NSString stringWithFormat :
2013-06-18 21:23:20 -04:00
@ "%@/social/river_stories/?global_feed=true&page=%d" ,
2012-12-07 15:17:22 -08:00
NEWSBLUR_URL ,
self . feedPage ] ;
} else {
theFeedDetailURL = [ NSString stringWithFormat :
2013-06-18 21:23:20 -04:00
@ "%@/social/river_stories/?page=%d" ,
2012-12-07 15:17:22 -08:00
NEWSBLUR_URL ,
self . feedPage ] ;
}
2013-02-06 15:15:43 -08:00
} else if ( [ appDelegate . activeFolder isEqual : @ "saved_stories" ] ) {
2012-10-17 15:07:53 -07:00
theFeedDetailURL = [ NSString stringWithFormat :
2013-06-18 21:23:20 -04:00
@ "%@/reader/starred_stories/?page=%d" ,
2012-10-17 15:07:53 -07:00
NEWSBLUR_URL ,
self . feedPage ] ;
2012-08-08 10:57:38 -07:00
} else {
theFeedDetailURL = [ NSString stringWithFormat :
2013-07-15 12:26:21 -07:00
@ "%@/reader/river_stories/?f=%@&page=%d" ,
2012-08-08 10:57:38 -07:00
NEWSBLUR_URL ,
2013-07-15 12:26:21 -07:00
[ appDelegate . activeFolderFeeds componentsJoinedByString : @ "&f=" ] ,
2012-10-03 15:46:02 -07:00
self . feedPage ] ;
2012-08-08 10:57:38 -07:00
}
2012-06-29 10:20:06 -07:00
2012-10-30 17:05:39 -07:00
2013-06-21 18:35:06 -07:00
theFeedDetailURL = [ NSString stringWithFormat : @ "%@&order=%@" ,
theFeedDetailURL ,
[ appDelegate activeOrder ] ] ;
theFeedDetailURL = [ NSString stringWithFormat : @ "%@&read_filter=%@" ,
theFeedDetailURL ,
[ appDelegate activeReadFilter ] ] ;
2012-10-30 17:05:39 -07:00
2012-06-29 10:20:06 -07:00
[ self cancelRequests ] ;
2012-07-15 15:06:06 -07:00
__weak ASIHTTPRequest * request = [ self requestWithURL : theFeedDetailURL ] ;
2012-06-29 10:20:06 -07:00
[ request setDelegate : self ] ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setFailedBlock : ^ ( void ) {
2013-07-17 19:22:41 -07:00
if ( request . isCancelled ) {
NSLog ( @ "Cancelled" ) ;
return ;
2013-10-10 12:58:40 -07:00
} else {
2013-06-20 20:38:40 -07:00
self . isOffline = YES ;
2013-08-12 11:59:07 -07:00
self . isShowingOffline = NO ;
2013-10-10 12:58:40 -07:00
self . feedPage = 1 ;
2013-06-20 20:38:40 -07:00
[ self loadOfflineStories ] ;
[ self showOfflineNotifier ] ;
}
2012-06-29 10:20:06 -07:00
} ] ;
[ request setCompletionBlock : ^ ( void ) {
[ self finishedLoadingFeed : request ] ;
if ( callback ) {
callback ( ) ;
}
} ] ;
[ request setTimeOutSeconds : 30 ] ;
[ request startAsynchronous ] ;
}
}
# pragma mark -
# pragma mark Processing Stories
2011-09-05 22:06:31 -07:00
- ( void ) finishedLoadingFeed : ( ASIHTTPRequest * ) request {
2013-07-17 19:22:41 -07:00
if ( request . isCancelled ) {
NSLog ( @ "Cancelled" ) ;
return ;
} else if ( [ request responseStatusCode ] >= 500 ) {
2013-10-10 12:58:40 -07:00
self . isOffline = YES ;
self . isShowingOffline = NO ;
self . feedPage = 1 ;
[ self loadOfflineStories ] ;
[ self showOfflineNotifier ] ;
2013-07-17 19:22:41 -07:00
if ( [ request responseStatusCode ] = = 503 ) {
[ self informError : @ "In maintenance mode" ] ;
2013-07-31 18:42:18 -07:00
self . pageFinished = YES ;
2013-06-13 21:56:13 -07:00
} else {
2013-06-20 20:38:40 -07:00
[ self informError : @ "The server barfed." ] ;
2013-06-13 21:56:13 -07:00
}
2013-06-20 20:38:40 -07:00
[ self . storyTitlesTable reloadData ] ;
2011-11-30 09:38:31 -08:00
return ;
}
2013-06-20 20:38:40 -07:00
2013-07-17 19:22:41 -07:00
appDelegate . hasLoadedFeedDetail = YES ;
2013-06-20 20:38:40 -07:00
self . isOffline = NO ;
2013-08-12 11:59:07 -07:00
self . isShowingOffline = NO ;
2011-09-05 22:06:31 -07:00
NSString * responseString = [ request responseString ] ;
2012-07-27 16:21:44 -07:00
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
2012-12-12 09:02:35 -08:00
id feedId = [ results objectForKey : @ "feed_id" ] ;
2012-12-27 00:15:26 -08:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2012-08-08 10:57:38 -07:00
if ( ! ( appDelegate . isRiverView || appDelegate . isSocialView || appDelegate . isSocialRiverView )
2012-12-12 09:02:35 -08:00
&& request . tag ! = [ feedId intValue ] ) {
2011-10-26 20:09:28 -07:00
return ;
}
2012-08-08 10:57:38 -07:00
if ( appDelegate . isSocialView || appDelegate . isSocialRiverView ) {
2012-06-26 16:24:19 -07:00
NSArray * newFeeds = [ results objectForKey : @ "feeds" ] ;
for ( int i = 0 ; i < newFeeds . count ; i + + ) {
NSString * feedKey = [ NSString stringWithFormat : @ "%@" , [ [ newFeeds objectAtIndex : i ] objectForKey : @ "id" ] ] ;
[ appDelegate . dictActiveFeeds setObject : [ newFeeds objectAtIndex : i ]
forKey : feedKey ] ;
}
2012-06-29 10:20:06 -07:00
[ self loadFaviconsFromActiveFeed ] ;
2012-06-26 16:24:19 -07:00
}
2012-12-07 16:17:48 -08:00
2012-12-11 11:50:06 -08:00
NSMutableDictionary * newClassifiers = [ [ results objectForKey : @ "classifiers" ] mutableCopy ] ;
2012-12-12 09:02:35 -08:00
if ( appDelegate . isRiverView || appDelegate . isSocialView || appDelegate . isSocialRiverView ) {
for ( id key in [ newClassifiers allKeys ] ) {
[ appDelegate . activeClassifiers setObject : [ newClassifiers objectForKey : key ] forKey : key ] ;
}
2013-10-01 19:32:40 -07:00
} else if ( newClassifiers ) {
2012-12-12 15:08:24 -08:00
[ appDelegate . activeClassifiers setObject : newClassifiers forKey : feedIdStr ] ;
2012-12-11 11:50:06 -08:00
}
2012-12-27 00:15:26 -08:00
appDelegate . activePopularAuthors = [ results objectForKey : @ "feed_authors" ] ;
appDelegate . activePopularTags = [ results objectForKey : @ "feed_tags" ] ;
2012-12-07 16:17:48 -08:00
2011-10-26 20:09:28 -07:00
NSArray * newStories = [ results objectForKey : @ "stories" ] ;
2012-08-06 15:46:05 -07:00
NSMutableArray * confirmedNewStories = [ [ NSMutableArray alloc ] init ] ;
2013-06-13 17:56:58 -07:00
if ( self . feedPage = = 1 ) {
confirmedNewStories = [ newStories copy ] ;
} else {
2011-10-26 20:09:28 -07:00
NSMutableSet * storyIds = [ NSMutableSet set ] ;
for ( id story in appDelegate . activeFeedStories ) {
[ storyIds addObject : [ story objectForKey : @ "id" ] ] ;
}
for ( id story in newStories ) {
if ( ! [ storyIds containsObject : [ story objectForKey : @ "id" ] ] ) {
[ confirmedNewStories addObject : story ] ;
2011-10-26 09:05:59 -07:00
}
}
2011-09-06 17:51:02 -07:00
}
2012-06-22 18:01:08 -07:00
// Adding new user profiles to appDelegate . activeFeedUserProfiles
2012-08-15 15:38:21 -07:00
NSArray * newUserProfiles = [ [ NSArray alloc ] init ] ;
if ( [ results objectForKey : @ "user_profiles" ] ! = nil ) {
newUserProfiles = [ results objectForKey : @ "user_profiles" ] ;
}
2012-07-20 00:21:24 -07:00
// add self to user profiles
if ( self . feedPage = = 1 ) {
2013-03-04 20:21:29 -08:00
newUserProfiles = [ newUserProfiles arrayByAddingObject : appDelegate . dictSocialProfile ] ;
2012-07-20 00:21:24 -07:00
}
2012-06-22 18:01:08 -07:00
if ( [ newUserProfiles count ] ) {
NSMutableArray * confirmedNewUserProfiles = [ NSMutableArray array ] ;
if ( [ appDelegate . activeFeedUserProfiles count ] ) {
NSMutableSet * userProfileIds = [ NSMutableSet set ] ;
for ( id userProfile in appDelegate . activeFeedUserProfiles ) {
[ userProfileIds addObject : [ userProfile objectForKey : @ "id" ] ] ;
}
for ( id userProfile in newUserProfiles ) {
if ( ! [ userProfileIds containsObject : [ userProfile objectForKey : @ "id" ] ] ) {
[ confirmedNewUserProfiles addObject : userProfile ] ;
}
}
} else {
2012-07-15 15:06:06 -07:00
confirmedNewUserProfiles = [ newUserProfiles copy ] ;
2012-06-22 18:01:08 -07:00
}
2012-07-16 10:10:52 -07:00
if ( self . feedPage = = 1 ) {
[ appDelegate setFeedUserProfiles : confirmedNewUserProfiles ] ;
} else if ( newUserProfiles . count > 0 ) {
[ appDelegate addFeedUserProfiles : confirmedNewUserProfiles ] ;
}
2012-07-15 18:23:08 -07:00
// NSLog ( @ "activeFeedUserProfiles is %@" , appDelegate . activeFeedUserProfiles ) ;
2012-07-01 21:58:55 -07:00
// NSLog ( @ "# of user profiles added: %i" , appDelegate . activeFeedUserProfiles . count ) ;
// NSLog ( @ "user profiles added: %@" , appDelegate . activeFeedUserProfiles ) ;
2012-06-22 18:01:08 -07:00
}
2013-06-13 21:56:13 -07:00
self . pageFinished = NO ;
2011-10-26 20:09:28 -07:00
[ self renderStories : confirmedNewStories ] ;
2012-11-06 17:26:08 -08:00
[ appDelegate . storyPageControl resizeScrollView ] ;
2012-12-06 15:30:16 -08:00
[ appDelegate . storyPageControl setStoryFromScroll : YES ] ;
2012-12-13 16:41:52 -08:00
[ appDelegate . storyPageControl advanceToNextUnread ] ;
2013-06-20 19:25:57 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
[ appDelegate . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
for ( NSDictionary * story in confirmedNewStories ) {
[ db executeUpdate : @ "INSERT into stories"
2013-06-23 22:19:08 -07:00
"(story_feed_id, story_hash, story_timestamp, story_json) VALUES "
"(?, ?, ?, ?)" ,
2013-06-20 19:25:57 -07:00
[ story objectForKey : @ "story_feed_id" ] ,
[ story objectForKey : @ "story_hash" ] ,
[ story objectForKey : @ "story_timestamp" ] ,
[ story JSONRepresentation ]
] ;
}
// NSLog ( @ "Inserting %d stories: %@" , [ confirmedNewStories count ] , [ db lastErrorMessage ] ) ;
} ] ;
} ) ;
2013-06-07 02:47:43 -04:00
2013-06-12 19:49:10 -07:00
[ self . notifier hide ] ;
2011-08-21 13:46:43 -07:00
}
2013-06-05 17:11:01 -07:00
# pragma mark -
2011-10-25 09:47:55 -07:00
# pragma mark Stories
2011-08-21 13:46:43 -07:00
- ( void ) renderStories : ( NSArray * ) newStories {
2013-09-10 16:02:49 -07:00
2011-08-09 17:58:43 -07:00
NSInteger newStoriesCount = [ newStories count ] ;
2011-07-22 09:10:13 -07:00
2013-06-13 17:56:58 -07:00
if ( newStoriesCount > 0 ) {
if ( self . feedPage = = 1 ) {
[ appDelegate setStories : newStories ] ;
} else {
[ appDelegate addStories : newStories ] ;
2011-07-22 09:10:13 -07:00
}
2013-09-10 16:02:49 -07:00
} else {
2011-07-24 16:52:24 -07:00
self . pageFinished = YES ;
2011-07-20 22:21:11 -07:00
}
2013-09-10 16:02:49 -07:00
[ self . storyTitlesTable reloadData ] ;
2011-07-20 22:21:11 -07:00
self . pageFetching = NO ;
2013-02-21 17:57:32 -08:00
if ( self . finishedAnimatingIn ) {
[ self testForTryFeed ] ;
}
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
[ appDelegate . masterContainerViewController syncNextPreviousButtons ] ;
}
2011-07-24 16:52:24 -07:00
2013-02-21 17:57:32 -08:00
[ self performSelector : @ selector ( checkScroll )
withObject : nil
2013-02-22 16:02:45 -08:00
afterDelay : 0.1 ] ;
2013-02-21 17:57:32 -08:00
}
- ( void ) testForTryFeed {
2012-07-16 22:35:28 -07:00
if ( appDelegate . inFindingStoryMode && appDelegate . tryFeedStoryId ) {
2012-07-16 19:45:14 -07:00
for ( int i = 0 ; i < appDelegate . activeFeedStories . count ; i + + ) {
NSString * storyIdStr = [ [ appDelegate . activeFeedStories objectAtIndex : i ] objectForKey : @ "id" ] ;
if ( [ storyIdStr isEqualToString : appDelegate . tryFeedStoryId ] ) {
NSDictionary * feed = [ appDelegate . activeFeedStories objectAtIndex : i ] ;
2013-09-25 17:43:00 -07:00
NSInteger score = [ NewsBlurAppDelegate computeStoryScore : [ feed objectForKey : @ "intelligence" ] ] ;
2012-07-16 19:45:14 -07:00
if ( score < appDelegate . selectedIntelligence ) {
[ self changeIntelligence : score ] ;
}
2013-09-25 17:43:00 -07:00
NSInteger locationOfStoryId = [ appDelegate locationOfStoryId : storyIdStr ] ;
2012-07-16 19:45:14 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : locationOfStoryId inSection : 0 ] ;
2013-02-21 17:57:32 -08:00
2012-07-16 19:45:14 -07:00
[ self . storyTitlesTable selectRowAtIndexPath : indexPath animated : YES scrollPosition : UITableViewScrollPositionBottom ] ;
2012-07-23 10:57:11 -07:00
FeedDetailTableCell * cell = ( FeedDetailTableCell * ) [ self . storyTitlesTable cellForRowAtIndexPath : indexPath ] ;
2012-07-31 23:49:51 -07:00
[ self loadStory : cell atRow : indexPath . row ] ;
2012-08-01 12:41:02 -07:00
2013-09-11 17:05:47 -07:00
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
2012-08-01 12:41:02 -07:00
// found the story , reset the two flags .
2013-02-21 17:57:32 -08:00
// appDelegate . tryFeedStoryId = nil ;
2012-08-01 12:41:02 -07:00
appDelegate . inFindingStoryMode = NO ;
2012-07-16 19:45:14 -07:00
}
}
}
2010-06-21 17:17:26 -04:00
}
2011-07-24 20:34:54 -07:00
- ( void ) connection : ( NSURLConnection * ) connection didFailWithError : ( NSError * ) error {
2010-07-15 23:32:37 -04:00
// inform the user
2010-11-15 19:40:17 -05:00
NSLog ( @ "Connection failed! Error - %@" ,
[ error localizedDescription ] ) ;
2011-07-20 22:21:11 -07:00
self . pageFetching = NO ;
2011-08-18 09:56:52 -07:00
// User clicking on another link before the page loads is OK .
if ( [ error code ] ! = NSURLErrorCancelled ) {
2011-10-27 09:44:58 -07:00
[ self informError : error ] ;
2011-08-18 09:56:52 -07:00
}
2010-07-15 23:32:37 -04:00
}
2011-07-24 16:52:24 -07:00
- ( UITableViewCell * ) makeLoadingCell {
2013-09-25 17:43:00 -07:00
NSInteger height = 40 ;
2013-06-12 19:21:56 -07:00
UITableViewCell * cell = [ [ UITableViewCell alloc ]
initWithStyle : UITableViewCellStyleSubtitle
reuseIdentifier : @ "NoReuse" ] ;
2011-07-24 17:18:05 -07:00
cell . selectionStyle = UITableViewCellSelectionStyleNone ;
2013-06-12 19:21:56 -07:00
2011-07-24 16:52:24 -07:00
if ( self . pageFinished ) {
2012-07-09 18:17:01 -07:00
UIImage * img = [ UIImage imageNamed : @ "fleuron.png" ] ;
UIImageView * fleuron = [ [ UIImageView alloc ] initWithImage : img ] ;
2012-08-08 18:23:48 -07:00
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad
&& ! appDelegate . masterContainerViewController . storyTitlesOnLeft
&& UIInterfaceOrientationIsPortrait ( orientation ) ) {
height = height - kTableViewShortRowDifference ;
}
2012-07-09 18:17:01 -07:00
fleuron . frame = CGRectMake ( 0 , 0 , self . view . frame . size . width , height ) ;
fleuron . contentMode = UIViewContentModeCenter ;
[ cell . contentView addSubview : fleuron ] ;
2013-09-24 17:18:20 -07:00
cell . backgroundColor = [ UIColor clearColor ] ;
2013-06-12 19:21:56 -07:00
return cell ;
2013-06-13 17:56:58 -07:00
} else { // if ( [ appDelegate . storyLocationsCount ] ) {
2013-06-12 19:21:56 -07:00
NBLoadingCell * loadingCell = [ [ NBLoadingCell alloc ] initWithFrame : CGRectMake ( 0 , 0 , self . view . frame . size . width , height ) ] ;
return loadingCell ;
2011-07-24 16:52:24 -07:00
}
return cell ;
}
2010-06-21 17:17:26 -04:00
2010-06-24 00:22:26 -04:00
# pragma mark -
# pragma mark Table View - Feed List
2010-06-21 17:17:26 -04:00
2012-06-15 19:12:48 -07:00
- ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section {
2013-09-25 17:43:00 -07:00
NSInteger storyCount = appDelegate . storyLocationsCount ;
2011-08-21 13:46:43 -07:00
2012-06-15 19:12:48 -07:00
// The + 1 is for the finished / loading bar .
return storyCount + 1 ;
2010-06-21 17:17:26 -04:00
}
2011-08-13 17:08:26 -07:00
- ( UITableViewCell * ) tableView : ( UITableView * ) tableView
cellForRowAtIndexPath : ( NSIndexPath * ) indexPath {
2012-06-29 10:20:06 -07:00
2012-07-22 17:21:32 -07:00
NSString * cellIdentifier ;
2012-06-26 16:24:19 -07:00
NSDictionary * feed ;
2013-09-27 17:23:03 -07:00
if ( indexPath . row >= appDelegate . storyLocationsCount ) {
return [ self makeLoadingCell ] ;
}
2012-06-26 16:24:19 -07:00
if ( appDelegate . isRiverView || appDelegate . isSocialView ) {
2011-10-26 20:09:28 -07:00
cellIdentifier = @ "FeedRiverDetailCellIdentifier" ;
2011-10-25 09:28:05 -07:00
} else {
cellIdentifier = @ "FeedDetailCellIdentifier" ;
}
2012-07-22 17:08:29 -07:00
2013-09-27 17:23:03 -07:00
FeedDetailTableCell * cell = ( FeedDetailTableCell * ) [ tableView
dequeueReusableCellWithIdentifier : cellIdentifier ] ;
2012-07-22 17:08:29 -07:00
if ( cell = = nil ) {
cell = [ [ FeedDetailTableCell alloc ] initWithStyle : UITableViewCellStyleDefault
2012-07-22 17:21:32 -07:00
reuseIdentifier : nil ] ;
2012-07-22 17:08:29 -07:00
}
2013-09-27 17:23:03 -07:00
2011-07-29 09:06:17 -07:00
NSDictionary * story = [ self getStoryAtRow : indexPath . row ] ;
2012-06-26 16:24:19 -07:00
2011-10-26 20:09:28 -07:00
id feedId = [ story objectForKey : @ "story_feed_id" ] ;
2012-06-26 16:24:19 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2012-08-08 10:57:38 -07:00
if ( appDelegate . isSocialView || appDelegate . isSocialRiverView ) {
2012-06-26 16:24:19 -07:00
feed = [ appDelegate . dictActiveFeeds objectForKey : feedIdStr ] ;
// this is to catch when a user is already subscribed
if ( ! feed ) {
feed = [ appDelegate . dictFeeds objectForKey : feedIdStr ] ;
}
} else {
feed = [ appDelegate . dictFeeds objectForKey : feedIdStr ] ;
}
2012-07-22 17:08:29 -07:00
NSString * siteTitle = [ feed objectForKey : @ "feed_title" ] ;
cell . siteTitle = siteTitle ;
NSString * title = [ story objectForKey : @ "story_title" ] ;
cell . storyTitle = [ title stringByDecodingHTMLEntities ] ;
2013-10-10 12:58:40 -07:00
2012-07-22 17:08:29 -07:00
cell . storyDate = [ story objectForKey : @ "short_parsed_date" ] ;
2013-10-10 12:58:40 -07:00
cell . storyTimestamp = [ [ story objectForKey : @ "story_timestamp" ] integerValue ] ;
2013-10-01 14:19:12 -07:00
cell . isStarred = [ [ story objectForKey : @ "starred" ] boolValue ] ;
cell . isShared = [ [ story objectForKey : @ "shared" ] boolValue ] ;
2011-10-26 20:09:28 -07:00
2010-07-15 00:44:38 -04:00
if ( [ [ story objectForKey : @ "story_authors" ] class ] ! = [ NSNull class ] ) {
2012-07-22 17:08:29 -07:00
cell . storyAuthor = [ [ story objectForKey : @ "story_authors" ] uppercaseString ] ;
2010-07-15 00:44:38 -04:00
} else {
2012-07-22 17:08:29 -07:00
cell . storyAuthor = @ "" ;
2011-10-27 19:05:38 -07:00
}
2012-06-26 16:24:19 -07:00
2012-07-22 17:08:29 -07:00
// feed color bar border
unsigned int colorBorder = 0 ;
2013-02-14 15:36:21 -08:00
NSString * faviconColor = [ feed valueForKey : @ "favicon_fade" ] ;
2010-07-15 00:44:38 -04:00
2013-08-05 18:32:43 -07:00
if ( [ faviconColor class ] = = [ NSNull class ] || ! faviconColor ) {
2013-02-14 15:36:21 -08:00
faviconColor = @ "707070" ;
2012-07-22 17:08:29 -07:00
}
NSScanner * scannerBorder = [ NSScanner scannerWithString : faviconColor ] ;
[ scannerBorder scanHexInt : & colorBorder ] ;
2010-06-21 17:17:26 -04:00
2012-07-22 17:08:29 -07:00
cell . feedColorBar = UIColorFromRGB ( colorBorder ) ;
2012-07-22 14:23:50 -07:00
2012-07-22 17:08:29 -07:00
// feed color bar border
2013-02-14 15:36:21 -08:00
NSString * faviconFade = [ feed valueForKey : @ "favicon_color" ] ;
2013-08-05 18:32:43 -07:00
if ( [ faviconFade class ] = = [ NSNull class ] || ! faviconFade ) {
2012-07-22 14:23:50 -07:00
faviconFade = @ "505050" ;
}
2012-07-22 17:08:29 -07:00
scannerBorder = [ NSScanner scannerWithString : faviconFade ] ;
2012-07-22 14:23:50 -07:00
[ scannerBorder scanHexInt : & colorBorder ] ;
2012-07-22 17:08:29 -07:00
cell . feedColorBarTopBorder = UIColorFromRGB ( colorBorder ) ;
// favicon
cell . siteFavicon = [ Utilities getImage : feedIdStr ] ;
// undread indicator
2013-09-25 17:43:00 -07:00
NSInteger score = [ NewsBlurAppDelegate computeStoryScore : [ story objectForKey : @ "intelligence" ] ] ;
2012-08-10 18:10:07 -07:00
cell . storyScore = score ;
2012-10-16 17:24:01 -07:00
2013-10-04 16:41:22 -07:00
cell . isRead = ! [ appDelegate isStoryUnread : story ] ;
// if ( ! appDelegate . hasLoadedFeedDetail ) {
2013-10-03 18:07:39 -07:00
// NSLog ( @ "Offline: %d (%d/%d) - %@ - %@" , cell . isRead , ! [ [ appDelegate . unreadStoryHashes objectForKey : [ story objectForKey : @ "story_hash" ] ] boolValue ] , [ [ appDelegate . recentlyReadStories objectForKey : [ story objectForKey : @ "story_hash" ] ] boolValue ] , [ story objectForKey : @ "story_title" ] , [ story objectForKey : @ "story_hash" ] ) ;
2013-10-04 16:41:22 -07:00
// } else {
2013-10-03 18:07:39 -07:00
// NSLog ( @ "Online: %d (%d/%d) - %@ - %@" , cell . isRead , [ [ story objectForKey : @ "read_status" ] intValue ] = = 1 , [ [ appDelegate . recentlyReadStories objectForKey : [ story objectForKey : @ "story_hash" ] ] boolValue ] , [ story objectForKey : @ "story_title" ] , [ story objectForKey : @ "story_hash" ] ) ;
2013-10-04 16:41:22 -07:00
// }
2012-08-08 18:23:48 -07:00
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad
&& ! appDelegate . masterContainerViewController . storyTitlesOnLeft
&& UIInterfaceOrientationIsPortrait ( orientation ) ) {
cell . isShort = YES ;
}
2012-07-22 14:23:50 -07:00
2012-08-08 10:57:38 -07:00
if ( appDelegate . isRiverView || appDelegate . isSocialView || appDelegate . isSocialRiverView ) {
2012-07-23 10:57:11 -07:00
cell . isRiverOrSocial = YES ;
}
2012-07-22 14:23:50 -07:00
2013-09-27 17:23:03 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2013-09-25 17:43:00 -07:00
NSInteger rowIndex = [ appDelegate locationOfActiveStory ] ;
2012-08-07 09:57:21 -07:00
if ( rowIndex = = indexPath . row ) {
[ self . storyTitlesTable selectRowAtIndexPath : indexPath animated : NO scrollPosition : UITableViewScrollPositionNone ] ;
}
}
2013-10-01 15:38:29 -07:00
[ cell setupGestures ] ;
2012-08-06 15:46:05 -07:00
2013-09-27 17:23:03 -07:00
return cell ;
2012-07-22 17:08:29 -07:00
}
2013-09-24 17:18:20 -07:00
- ( void ) loadStory : ( FeedDetailTableCell * ) cell atRow : ( NSInteger ) row {
2013-09-25 17:43:00 -07:00
NSInteger storyIndex = [ appDelegate indexFromLocation : row ] ;
2012-11-06 17:26:08 -08:00
appDelegate . activeStory = [ [ appDelegate activeFeedStories ] objectAtIndex : storyIndex ] ;
2013-10-04 12:37:51 -07:00
if ( [ appDelegate isStoryUnread : appDelegate . activeStory ] ) {
[ self markStoryAsRead : appDelegate . activeStory ] ;
}
2012-07-16 19:45:14 -07:00
[ appDelegate loadStoryDetailView ] ;
2013-10-04 16:41:22 -07:00
[ self redrawUnreadStory ] ;
2012-07-16 19:45:14 -07:00
}
2012-10-16 17:24:01 -07:00
- ( void ) redrawUnreadStory {
2013-09-25 17:43:00 -07:00
NSInteger rowIndex = [ appDelegate locationOfActiveStory ] ;
2012-10-16 17:24:01 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : rowIndex inSection : 0 ] ;
FeedDetailTableCell * cell = ( FeedDetailTableCell * ) [ self . storyTitlesTable cellForRowAtIndexPath : indexPath ] ;
2013-10-04 12:37:51 -07:00
cell . isRead = ! [ appDelegate isStoryUnread : appDelegate . activeStory ] ;
2013-08-05 17:29:42 -07:00
cell . isShared = [ [ appDelegate . activeStory objectForKey : @ "shared" ] boolValue ] ;
cell . isStarred = [ [ appDelegate . activeStory objectForKey : @ "starred" ] boolValue ] ;
2012-10-16 17:24:01 -07:00
[ cell setNeedsDisplay ] ;
}
2012-07-29 20:55:11 -07:00
- ( void ) changeActiveStoryTitleCellLayout {
2013-09-25 17:43:00 -07:00
NSInteger rowIndex = [ appDelegate locationOfActiveStory ] ;
2012-07-27 15:01:03 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : rowIndex inSection : 0 ] ;
FeedDetailTableCell * cell = ( FeedDetailTableCell * ) [ self . storyTitlesTable cellForRowAtIndexPath : indexPath ] ;
cell . isRead = YES ;
[ cell setNeedsLayout ] ;
}
2010-06-21 17:17:26 -04:00
- ( void ) tableView : ( UITableView * ) tableView didSelectRowAtIndexPath : ( NSIndexPath * ) indexPath {
2013-06-13 17:56:58 -07:00
if ( indexPath . row < appDelegate . storyLocationsCount ) {
2012-07-29 13:24:03 -07:00
// mark the cell as read
2012-07-23 10:57:11 -07:00
FeedDetailTableCell * cell = ( FeedDetailTableCell * ) [ tableView cellForRowAtIndexPath : indexPath ] ;
2012-11-06 17:26:08 -08:00
[ self loadStory : cell atRow : indexPath . row ] ;
2011-07-24 16:52:24 -07:00
}
2010-06-21 17:17:26 -04:00
}
2013-06-12 19:21:56 -07:00
- ( void ) tableView : ( UITableView * ) tableView didEndDisplayingCell : ( UITableViewCell * ) cell forRowAtIndexPath : ( NSIndexPath * ) indexPath {
if ( [ cell class ] = = [ NBLoadingCell class ] ) {
[ ( NBLoadingCell * ) cell endAnimation ] ;
}
}
- ( void ) tableView : ( UITableView * ) tableView willDisplayCell : ( UITableViewCell * ) cell forRowAtIndexPath : ( NSIndexPath * ) indexPath {
if ( [ cell class ] = = [ NBLoadingCell class ] ) {
[ ( NBLoadingCell * ) cell animate ] ;
}
}
2013-10-17 18:56:14 -07:00
- ( CGFloat ) tableView : ( UITableView * ) tableView
heightForRowAtIndexPath : ( NSIndexPath * ) indexPath {
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
2013-06-12 17:36:09 -07:00
2013-09-25 17:43:00 -07:00
NSInteger storyCount = appDelegate . storyLocationsCount ;
2013-06-12 19:21:56 -07:00
if ( storyCount && indexPath . row = = storyCount ) {
2013-06-11 23:00:00 -07:00
return 40 ;
2013-06-10 00:29:03 -07:00
} else if ( appDelegate . isRiverView || appDelegate . isSocialView || appDelegate . isSocialRiverView ) {
2013-09-25 17:43:00 -07:00
NSInteger height = kTableViewRiverRowHeight ;
2012-08-08 18:23:48 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad
&& ! appDelegate . masterContainerViewController . storyTitlesOnLeft
&& UIInterfaceOrientationIsPortrait ( orientation ) ) {
height = height - kTableViewShortRowDifference ;
}
2013-11-23 13:03:14 -08:00
UIFontDescriptor * fontDescriptor = [ self fontDescriptorUsingPreferredSize : UIFontTextStyleCaption1 ] ;
2013-10-17 18:56:14 -07:00
UIFont * font = [ UIFont fontWithDescriptor : fontDescriptor size : 0.0 ] ;
return height + font . pointSize * 2 ;
2011-07-24 16:52:24 -07:00
} else {
2013-09-25 17:43:00 -07:00
NSInteger height = kTableViewRowHeight ;
2012-08-08 18:23:48 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad
&& ! appDelegate . masterContainerViewController . storyTitlesOnLeft
&& UIInterfaceOrientationIsPortrait ( orientation ) ) {
height = height - kTableViewShortRowDifference ;
}
2013-11-23 13:03:14 -08:00
UIFontDescriptor * fontDescriptor = [ self fontDescriptorUsingPreferredSize : UIFontTextStyleCaption1 ] ;
2013-10-17 18:56:14 -07:00
UIFont * font = [ UIFont fontWithDescriptor : fontDescriptor size : 0.0 ] ;
return height + font . pointSize * 2 ;
2011-07-24 16:52:24 -07:00
}
2010-07-15 00:44:38 -04:00
}
2013-09-24 17:18:20 -07:00
- ( CGFloat ) tableView : ( UITableView * ) tableView heightForFooterInSection : ( NSInteger ) section {
// This will create a "invisible" footer
return 0.01 f ;
}
2011-07-20 22:21:11 -07:00
- ( void ) scrollViewDidScroll : ( UIScrollView * ) scroll {
2011-07-29 21:56:54 -07:00
[ self checkScroll ] ;
}
2013-11-23 13:03:14 -08:00
- ( UIFontDescriptor * ) fontDescriptorUsingPreferredSize : ( NSString * ) textStyle {
UIFontDescriptor * fontDescriptor = [ UIFontDescriptor preferredFontDescriptorWithTextStyle : textStyle ] ;
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
if ( ! [ userPreferences boolForKey : @ "use_system_font_size" ] ) {
if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "xs" ] ) {
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 10.0 f ] ;
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "small" ] ) {
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 11.0 f ] ;
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "medium" ] ) {
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 12.0 f ] ;
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "large" ] ) {
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 14.0 f ] ;
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "xl" ] ) {
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 16.0 f ] ;
}
}
return fontDescriptor ;
}
2011-07-29 21:56:54 -07:00
- ( void ) checkScroll {
NSInteger currentOffset = self . storyTitlesTable . contentOffset . y ;
NSInteger maximumOffset = self . storyTitlesTable . contentSize . height - self . storyTitlesTable . frame . size . height ;
2011-07-20 22:21:11 -07:00
2013-09-05 18:48:23 -07:00
if ( ! [ self . appDelegate . activeFeedStories count ] ) return ;
2012-07-16 19:45:14 -07:00
if ( maximumOffset - currentOffset <= 60.0 ||
2012-07-16 22:35:28 -07:00
( appDelegate . inFindingStoryMode ) ) {
2011-10-26 08:40:31 -07:00
if ( appDelegate . isRiverView ) {
[ self fetchRiverPage : self . feedPage + 1 withCallback : nil ] ;
} else {
[ self fetchFeedDetail : self . feedPage + 1 withCallback : nil ] ;
}
2011-07-20 22:21:11 -07:00
}
}
2012-07-16 19:45:14 -07:00
- ( void ) changeIntelligence : ( NSInteger ) newLevel {
2011-07-29 09:06:17 -07:00
NSInteger previousLevel = [ appDelegate selectedIntelligence ] ;
2011-08-02 09:16:54 -07:00
if ( newLevel = = previousLevel ) return ;
2011-07-29 21:27:37 -07:00
if ( newLevel < previousLevel ) {
[ appDelegate setSelectedIntelligence : newLevel ] ;
2012-07-16 19:45:14 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
[ userPreferences setInteger : ( newLevel + 1 ) forKey : @ "selectedIntelligence" ] ;
[ userPreferences synchronize ] ;
2011-07-29 21:27:37 -07:00
[ appDelegate calculateStoryLocations ] ;
}
2012-07-16 19:45:14 -07:00
2013-09-11 17:05:47 -07:00
[ self . storyTitlesTable reloadData ] ;
2011-07-29 09:06:17 -07:00
}
- ( NSDictionary * ) getStoryAtRow : ( NSInteger ) indexPathRow {
2013-09-25 17:43:00 -07:00
NSInteger row = [ [ [ appDelegate activeFeedStoryLocations ] objectAtIndex : indexPathRow ] intValue ] ;
2011-07-29 09:06:17 -07:00
return [ appDelegate . activeFeedStories objectAtIndex : row ] ;
2011-07-24 22:23:38 -07:00
}
2013-09-27 17:23:03 -07:00
# pragma mark - MCSwipeTableViewCellDelegate
// When the user starts swiping the cell this method is called
- ( void ) swipeTableViewCellDidStartSwiping : ( MCSwipeTableViewCell * ) cell {
2013-09-30 16:18:11 -07:00
// NSLog ( @ "Did start swiping the cell!" ) ;
2013-09-27 17:23:03 -07:00
}
2013-09-30 16:18:11 -07:00
// When the user is dragging , this method is called and return the dragged percentage from the border
- ( void ) swipeTableViewCell : ( MCSwipeTableViewCell * ) cell didSwipWithPercentage : ( CGFloat ) percentage {
// NSLog ( @ "Did swipe with percentage : %f" , percentage ) ;
}
2013-09-27 17:23:03 -07:00
- ( void ) swipeTableViewCell : ( MCSwipeTableViewCell * ) cell didEndSwipingSwipingWithState : ( MCSwipeTableViewCellState ) state mode : ( MCSwipeTableViewCellMode ) mode {
2013-10-01 14:19:12 -07:00
NSIndexPath * indexPath = [ self . storyTitlesTable indexPathForCell : cell ] ;
2013-10-08 13:57:15 -07:00
if ( ! indexPath ) {
// This can happen if the user swipes on a cell that is being refreshed .
return ;
}
2013-10-01 14:19:12 -07:00
NSInteger storyIndex = [ appDelegate indexFromLocation : indexPath . row ] ;
NSDictionary * story = [ [ appDelegate activeFeedStories ] objectAtIndex : storyIndex ] ;
if ( state = = MCSwipeTableViewCellState1 ) {
// Saved
if ( [ [ story objectForKey : @ "starred" ] boolValue ] ) {
[ self markStoryAsUnsaved : story ] ;
} else {
[ self markStoryAsSaved : story ] ;
}
[ self . storyTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationFade ] ;
} else if ( state = = MCSwipeTableViewCellState3 ) {
// Read
2013-10-01 16:21:23 -07:00
if ( [ [ story objectForKey : @ "read_status" ] boolValue ] ) {
[ self markStoryAsUnread : story ] ;
2013-10-01 15:38:29 -07:00
} else {
2013-10-01 16:21:23 -07:00
[ self markStoryAsRead : story ] ;
2013-10-01 15:38:29 -07:00
}
[ self . storyTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationFade ] ;
2013-10-01 14:19:12 -07:00
}
2013-09-27 17:23:03 -07:00
}
2011-10-17 09:28:15 -07:00
# pragma mark -
# pragma mark Feed Actions
2013-10-09 14:54:49 -07:00
- ( void ) handleLongPress : ( UILongPressGestureRecognizer * ) gestureRecognizer {
CGPoint p = [ gestureRecognizer locationInView : self . storyTitlesTable ] ;
NSIndexPath * indexPath = [ self . storyTitlesTable indexPathForRowAtPoint : p ] ;
FeedDetailTableCell * cell = ( FeedDetailTableCell * ) [ self . storyTitlesTable cellForRowAtIndexPath : indexPath ] ;
if ( gestureRecognizer . state ! = UIGestureRecognizerStateBegan ) return ;
if ( indexPath = = nil ) return ;
NSDictionary * story = [ self getStoryAtRow : indexPath . row ] ;
appDelegate . activeStory = story ;
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
[ appDelegate . masterContainerViewController showSendToPopover : cell ] ;
} else {
[ self presentViewController : [ UIActivitiesControl activityViewControllerForView : self ]
animated : YES
completion : nil ] ;
}
}
2011-11-09 09:51:42 -08:00
- ( void ) markFeedsReadWithAllStories : ( BOOL ) includeHidden {
2013-09-30 16:18:11 -07:00
if ( appDelegate . isRiverView && includeHidden &&
2013-02-06 18:24:41 -08:00
[ appDelegate . activeFolder isEqualToString : @ "everything" ] ) {
2012-12-10 18:34:13 -08:00
// Mark folder as read
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_all_as_read" ,
2012-12-10 18:34:13 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setDelegate : nil ] ;
[ request startAsynchronous ] ;
[ appDelegate markActiveFolderAllRead ] ;
2013-09-30 16:18:11 -07:00
} else if ( appDelegate . isRiverView && includeHidden ) {
2011-11-09 09:51:42 -08:00
// Mark folder as read
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_feed_as_read" ,
2011-11-09 09:51:42 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
2011-11-29 17:57:20 -08:00
for ( id feed_id in [ appDelegate . dictFolders objectForKey : appDelegate . activeFolder ] ) {
[ request addPostValue : feed_id forKey : @ "feed_id" ] ;
}
2013-09-30 16:18:11 -07:00
[ request setUserInfo : @ { @ "feeds" : appDelegate . activeFolderFeeds } ] ;
[ request setDelegate : self ] ;
[ request setDidFinishSelector : @ selector ( finishMarkAllAsRead : ) ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
2011-11-09 09:51:42 -08:00
[ request startAsynchronous ] ;
2011-11-10 18:28:22 -08:00
[ appDelegate markActiveFolderAllRead ] ;
2013-09-30 16:18:11 -07:00
} else if ( ! appDelegate . isRiverView && includeHidden ) {
2011-11-09 09:51:42 -08:00
// Mark feed as read
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_feed_as_read" ,
2011-11-04 08:46:24 -07:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
2012-08-01 23:16:04 -07:00
[ request setPostValue : [ appDelegate . activeFeed objectForKey : @ "id" ] forKey : @ "feed_id" ] ;
[ request setDidFinishSelector : @ selector ( finishMarkAllAsRead : ) ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
2013-09-30 16:18:11 -07:00
[ request setUserInfo : @ { @ "feeds" : @ [ [ appDelegate . activeFeed objectForKey : @ "id" ] ] } ] ;
2012-08-01 23:16:04 -07:00
[ request setDelegate : self ] ;
2011-11-04 08:46:24 -07:00
[ request startAsynchronous ] ;
2012-08-01 23:16:04 -07:00
[ appDelegate markFeedAllRead : [ appDelegate . activeFeed objectForKey : @ "id" ] ] ;
2013-08-06 18:08:55 -07:00
} else if ( ! includeHidden ) {
2011-11-09 09:51:42 -08:00
// Mark visible stories as read
2011-11-10 18:28:22 -08:00
NSDictionary * feedsStories = [ appDelegate markVisibleStoriesRead ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_feed_stories_as_read" ,
2011-11-09 09:51:42 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
2011-11-10 18:28:22 -08:00
[ request setPostValue : [ feedsStories JSONRepresentation ] forKey : @ "feeds_stories" ] ;
2012-08-01 23:16:04 -07:00
[ request setDelegate : self ] ;
2013-09-30 16:18:11 -07:00
[ request setUserInfo : @ { @ "stories" : feedsStories } ] ;
2012-08-01 23:16:04 -07:00
[ request setDidFinishSelector : @ selector ( finishMarkAllAsRead : ) ] ;
2013-08-06 18:08:55 -07:00
[ request setDidFailSelector : @ selector ( requestFailedMarkStoryRead : ) ] ;
2011-11-09 09:51:42 -08:00
[ request startAsynchronous ] ;
2012-08-01 23:16:04 -07:00
}
2013-09-30 16:18:11 -07:00
2012-08-01 23:16:04 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-08-06 19:21:39 -07:00
[ appDelegate . navigationController popToRootViewControllerAnimated : YES ] ;
2012-08-01 23:16:04 -07:00
[ appDelegate . masterContainerViewController transitionFromFeedDetail ] ;
} else {
2011-11-09 09:51:42 -08:00
[ appDelegate . navigationController
popToViewController : [ appDelegate . navigationController . viewControllers
objectAtIndex : 0 ]
animated : YES ] ;
2011-11-04 08:46:24 -07:00
}
}
2013-08-06 18:08:55 -07:00
- ( void ) requestFailedMarkStoryRead : ( ASIFormDataRequest * ) request {
// [ self informError : @ "Failed to mark story as read" ] ;
2013-09-30 16:18:11 -07:00
[ appDelegate markStoriesRead : [ request . userInfo objectForKey : @ "stories" ]
2013-10-08 19:33:11 -07:00
inFeeds : [ request . userInfo objectForKey : @ "feeds" ]
cutoffTimestamp : nil ] ;
2013-08-06 18:08:55 -07:00
}
- ( void ) finishMarkAllAsRead : ( ASIFormDataRequest * ) request {
if ( request . responseStatusCode ! = 200 ) {
[ self requestFailedMarkStoryRead : request ] ;
2013-09-30 16:18:11 -07:00
return ;
2013-08-06 18:08:55 -07:00
}
2012-08-01 23:16:04 -07:00
2013-10-17 11:21:37 -07:00
if ( [ request . userInfo objectForKey : @ "feeds" ] ) {
[ appDelegate markFeedReadInCache : @ [ [ request . userInfo objectForKey : @ "feeds" ] ] ] ;
}
2012-08-01 23:16:04 -07:00
}
2011-11-04 08:46:24 -07:00
- ( IBAction ) doOpenMarkReadActionSheet : ( id ) sender {
2012-08-08 19:31:33 -07:00
// already displaying action sheet ?
if ( self . actionSheet_ ) {
[ self . actionSheet_ dismissWithClickedButtonIndex : -1 animated : YES ] ;
self . actionSheet_ = nil ;
return ;
}
2011-11-29 17:57:20 -08:00
// Individual sites just get marked as read , no action sheet needed .
if ( ! appDelegate . isRiverView ) {
[ self markFeedsReadWithAllStories : YES ] ;
return ;
}
2011-11-09 09:51:42 -08:00
NSString * title = appDelegate . isRiverView ?
appDelegate . activeFolder :
[ appDelegate . activeFeed objectForKey : @ "feed_title" ] ;
2011-11-04 08:46:24 -07:00
UIActionSheet * options = [ [ UIActionSheet alloc ]
2011-11-09 09:51:42 -08:00
initWithTitle : title
2011-11-04 08:46:24 -07:00
delegate : self
cancelButtonTitle : nil
destructiveButtonTitle : nil
otherButtonTitles : nil ] ;
2012-08-08 19:31:33 -07:00
self . actionSheet_ = options ;
2013-08-06 18:08:55 -07:00
[ appDelegate calculateStoryLocations ] ;
2013-09-25 17:43:00 -07:00
NSInteger visibleUnreadCount = appDelegate . visibleUnreadCount ;
NSInteger totalUnreadCount = [ appDelegate unreadCount ] ;
2011-11-09 09:51:42 -08:00
NSArray * buttonTitles = nil ;
2011-12-05 18:10:40 -08:00
BOOL showVisible = YES ;
BOOL showEntire = YES ;
2012-12-10 18:34:13 -08:00
// if ( [ appDelegate . activeFolder isEqualToString : @ "everything" ] ) showEntire = NO ;
2012-10-17 15:07:53 -07:00
if ( visibleUnreadCount >= totalUnreadCount || visibleUnreadCount <= 0 ) showVisible = NO ;
2011-12-05 18:10:40 -08:00
NSString * entireText = [ NSString stringWithFormat : @ "Mark %@ read" ,
2012-12-10 18:34:13 -08:00
appDelegate . isRiverView ?
[ appDelegate . activeFolder isEqualToString : @ "everything" ] ?
@ "everything" :
2011-12-05 18:10:40 -08:00
@ "entire folder" :
@ "this site" ] ;
NSString * visibleText = [ NSString stringWithFormat : @ "Mark %@ read" ,
visibleUnreadCount = = 1 ? @ "this story as" :
2013-09-25 17:43:00 -07:00
[ NSString stringWithFormat : @ "these %ld stories" ,
( long ) visibleUnreadCount ] ] ;
2011-12-05 18:10:40 -08:00
if ( showVisible && showEntire ) {
2011-11-09 09:51:42 -08:00
buttonTitles = [ NSArray arrayWithObjects : visibleText , entireText , nil ] ;
options . destructiveButtonIndex = 1 ;
2011-12-05 18:10:40 -08:00
} else if ( showVisible && ! showEntire ) {
buttonTitles = [ NSArray arrayWithObjects : visibleText , nil ] ;
options . destructiveButtonIndex = -1 ;
} else if ( ! showVisible && showEntire ) {
buttonTitles = [ NSArray arrayWithObjects : entireText , nil ] ;
options . destructiveButtonIndex = 0 ;
2011-11-09 09:51:42 -08:00
}
2011-11-04 08:46:24 -07:00
for ( id title in buttonTitles ) {
[ options addButtonWithTitle : title ] ;
}
options . cancelButtonIndex = [ options addButtonWithTitle : @ "Cancel" ] ;
2011-11-05 16:25:04 -07:00
options . tag = kMarkReadActionSheet ;
2012-08-08 19:31:33 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
[ options showFromBarButtonItem : self . feedMarkReadButton animated : YES ] ;
} else {
[ options showInView : self . view ] ;
}
2011-11-04 08:46:24 -07:00
}
2011-10-17 09:28:15 -07:00
- ( void ) actionSheet : ( UIActionSheet * ) actionSheet clickedButtonAtIndex : ( NSInteger ) buttonIndex {
2011-12-03 18:22:14 -08:00
// NSLog ( @ "Action option #%d on %d" , buttonIndex , actionSheet . tag ) ;
2011-11-05 16:25:04 -07:00
if ( actionSheet . tag = = 1 ) {
2013-09-25 17:43:00 -07:00
NSInteger visibleUnreadCount = appDelegate . visibleUnreadCount ;
NSInteger totalUnreadCount = [ appDelegate unreadCount ] ;
2011-12-05 18:10:40 -08:00
BOOL showVisible = YES ;
BOOL showEntire = YES ;
2012-12-10 18:34:13 -08:00
// if ( [ appDelegate . activeFolder isEqualToString : @ "everything" ] ) showEntire = NO ;
2011-12-05 18:10:40 -08:00
if ( visibleUnreadCount >= totalUnreadCount || visibleUnreadCount <= 0 ) showVisible = NO ;
2011-12-03 18:22:14 -08:00
// NSLog ( @ "Counts: %d %d = %d" , visibleUnreadCount , totalUnreadCount , visibleUnreadCount >= totalUnreadCount || visibleUnreadCount <= 0 ) ;
2013-02-06 18:24:41 -08:00
2011-12-05 18:10:40 -08:00
if ( showVisible && showEntire ) {
2011-11-09 09:51:42 -08:00
if ( buttonIndex = = 0 ) {
2011-12-20 08:56:55 -08:00
[ self markFeedsReadWithAllStories : NO ] ;
} else if ( buttonIndex = = 1 ) {
[ self markFeedsReadWithAllStories : YES ] ;
}
2011-12-05 18:10:40 -08:00
} else if ( showVisible && ! showEntire ) {
2011-11-09 09:51:42 -08:00
if ( buttonIndex = = 0 ) {
[ self markFeedsReadWithAllStories : NO ] ;
2011-12-05 18:10:40 -08:00
}
} else if ( ! showVisible && showEntire ) {
if ( buttonIndex = = 0 ) {
2011-11-09 09:51:42 -08:00
[ self markFeedsReadWithAllStories : YES ] ;
2011-12-05 18:10:40 -08:00
}
2011-11-09 09:51:42 -08:00
}
2011-11-05 16:25:04 -07:00
} else if ( actionSheet . tag = = 2 ) {
if ( buttonIndex = = 0 ) {
[ self confirmDeleteSite ] ;
2011-12-03 18:22:14 -08:00
} else if ( buttonIndex = = 1 ) {
[ self openMoveView ] ;
2012-06-27 15:38:51 -07:00
} else if ( buttonIndex = = 2 ) {
[ self instafetchFeed ] ;
2011-11-05 16:25:04 -07:00
}
2013-10-08 19:33:11 -07:00
}
2011-10-17 09:28:15 -07:00
}
2012-08-08 19:31:33 -07:00
- ( void ) actionSheet : ( UIActionSheet * ) actionSheet didDismissWithButtonIndex : ( NSInteger ) buttonIndex {
// just set to nil
actionSheet_ = nil ;
}
2012-10-12 13:58:26 -04:00
- ( IBAction ) doOpenSettingsActionSheet : ( id ) sender {
2012-08-08 19:31:33 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2013-03-01 15:48:18 -08:00
[ appDelegate . masterContainerViewController showFeedDetailMenuPopover : self . settingsBarButton ] ;
2012-08-08 19:31:33 -07:00
} else {
2012-10-12 13:58:26 -04:00
if ( self . popoverController = = nil ) {
self . popoverController = [ [ WEPopoverController alloc ]
2012-10-15 14:57:20 -07:00
initWithContentViewController : ( UIViewController * ) appDelegate . feedDetailMenuViewController ] ;
2013-04-22 17:15:50 -07:00
[ appDelegate . feedDetailMenuViewController buildMenuOptions ] ;
2012-10-12 13:58:26 -04:00
self . popoverController . delegate = self ;
} else {
[ self . popoverController dismissPopoverAnimated : YES ] ;
self . popoverController = nil ;
}
if ( [ self . popoverController respondsToSelector : @ selector ( setContainerViewProperties : ) ] ) {
[ self . popoverController setContainerViewProperties : [ self improvedContainerViewProperties ] ] ;
}
2013-09-25 17:43:00 -07:00
NSInteger menuCount = [ appDelegate . feedDetailMenuViewController . menuOptions count ] + 2 ;
2013-04-22 17:15:50 -07:00
[ self . popoverController setPopoverContentSize : CGSizeMake ( 260 , 38 * menuCount ) ] ;
2013-02-27 17:22:49 -08:00
[ self . popoverController presentPopoverFromBarButtonItem : self . settingsBarButton
permittedArrowDirections : UIPopoverArrowDirectionUp
2012-10-12 13:58:26 -04:00
animated : YES ] ;
2012-08-08 19:31:33 -07:00
}
2012-10-12 13:58:26 -04:00
2011-12-20 08:56:55 -08:00
}
2011-10-17 09:28:15 -07:00
- ( void ) confirmDeleteSite {
2012-07-09 21:26:53 -07:00
UIAlertView * deleteConfirm = [ [ UIAlertView alloc ]
initWithTitle : @ "Positive?"
message : nil
delegate : self
cancelButtonTitle : @ "Cancel"
otherButtonTitles : @ "Delete" ,
nil ] ;
2011-10-17 09:28:15 -07:00
[ deleteConfirm show ] ;
[ deleteConfirm setTag : 0 ] ;
}
- ( void ) alertView : ( UIAlertView * ) alertView clickedButtonAtIndex : ( NSInteger ) buttonIndex {
if ( alertView . tag = = 0 ) {
if ( buttonIndex = = 0 ) {
return ;
} else {
2011-12-05 09:26:02 -08:00
if ( appDelegate . isRiverView ) {
[ self deleteFolder ] ;
} else {
[ self deleteSite ] ;
}
2011-10-17 09:28:15 -07:00
}
}
}
- ( void ) deleteSite {
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
MBProgressHUD * HUD = [ MBProgressHUD showHUDAddedTo : self . view animated : YES ] ;
HUD . labelText = @ "Deleting..." ;
2011-10-20 09:32:39 -07:00
2013-06-18 21:23:20 -04:00
NSString * theFeedDetailURL = [ NSString stringWithFormat : @ "%@/reader/delete_feed" ,
2011-10-20 09:32:39 -07:00
NEWSBLUR_URL ] ;
NSURL * urlFeedDetail = [ NSURL URLWithString : theFeedDetailURL ] ;
2013-06-04 17:56:10 -07:00
__block ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : urlFeedDetail ] ;
2011-10-20 09:32:39 -07:00
[ request setDelegate : self ] ;
[ request addPostValue : [ [ appDelegate activeFeed ] objectForKey : @ "id" ] forKey : @ "feed_id" ] ;
2011-12-04 21:09:16 -08:00
[ request addPostValue : [ appDelegate extractFolderName : appDelegate . activeFolder ] forKey : @ "in_folder" ] ;
2013-06-04 18:02:05 -07:00
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
2011-10-20 09:32:39 -07:00
[ request setCompletionBlock : ^ ( void ) {
2011-12-03 18:22:14 -08:00
[ appDelegate reloadFeedsView : YES ] ;
2011-10-20 09:32:39 -07:00
[ appDelegate . navigationController
popToViewController : [ appDelegate . navigationController . viewControllers
objectAtIndex : 0 ]
animated : YES ] ;
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
} ] ;
2013-06-03 12:43:45 -07:00
[ request setTimeOutSeconds : 30 ] ;
2011-10-20 09:32:39 -07:00
[ request setTag : [ [ [ appDelegate activeFeed ] objectForKey : @ "id" ] intValue ] ] ;
[ request startAsynchronous ] ;
2011-10-17 09:28:15 -07:00
}
2011-08-18 09:56:52 -07:00
2011-12-05 09:26:02 -08:00
- ( void ) deleteFolder {
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
MBProgressHUD * HUD = [ MBProgressHUD showHUDAddedTo : self . view animated : YES ] ;
HUD . labelText = @ "Deleting..." ;
2013-06-18 21:23:20 -04:00
NSString * theFeedDetailURL = [ NSString stringWithFormat : @ "%@/reader/delete_folder" ,
2011-12-05 09:26:02 -08:00
NEWSBLUR_URL ] ;
NSURL * urlFeedDetail = [ NSURL URLWithString : theFeedDetailURL ] ;
2013-06-04 17:56:10 -07:00
__block ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : urlFeedDetail ] ;
2011-12-05 09:26:02 -08:00
[ request setDelegate : self ] ;
[ request addPostValue : [ appDelegate extractFolderName : appDelegate . activeFolder ]
forKey : @ "folder_to_delete" ] ;
[ request addPostValue : [ appDelegate extractFolderName : [ appDelegate extractParentFolderName : appDelegate . activeFolder ] ]
forKey : @ "in_folder" ] ;
2013-06-04 18:02:05 -07:00
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
2011-12-05 09:26:02 -08:00
[ request setCompletionBlock : ^ ( void ) {
[ appDelegate reloadFeedsView : YES ] ;
[ appDelegate . navigationController
popToViewController : [ appDelegate . navigationController . viewControllers
objectAtIndex : 0 ]
animated : YES ] ;
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
} ] ;
[ request setTimeOutSeconds : 30 ] ;
[ request startAsynchronous ] ;
}
2011-12-03 18:22:14 -08:00
- ( void ) openMoveView {
[ appDelegate showMoveSite ] ;
}
2012-12-24 23:01:25 -08:00
- ( void ) openTrainSite {
[ appDelegate openTrainSite ] ;
}
2012-07-25 17:29:29 -07:00
- ( void ) showUserProfile {
2012-07-12 22:05:23 -07:00
appDelegate . activeUserProfileId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . activeFeed objectForKey : @ "user_id" ] ] ;
2012-07-28 14:15:20 -07:00
appDelegate . activeUserProfileName = [ NSString stringWithFormat : @ "%@" , [ appDelegate . activeFeed objectForKey : @ "username" ] ] ;
2013-10-11 17:46:09 -07:00
[ appDelegate showUserProfileModal : titleImageBarButton ] ;
2012-07-12 22:05:23 -07:00
}
2012-06-20 19:18:29 -07:00
- ( void ) changeActiveFeedDetailRow {
2013-09-25 17:43:00 -07:00
NSInteger rowIndex = [ appDelegate locationOfActiveStory ] ;
2012-06-21 11:53:48 -07:00
2012-06-18 16:45:36 -07:00
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : rowIndex inSection : 0 ] ;
NSIndexPath * offsetIndexPath = [ NSIndexPath indexPathForRow : rowIndex - 1 inSection : 0 ] ;
2012-06-18 17:20:34 -07:00
[ storyTitlesTable selectRowAtIndexPath : indexPath
animated : YES
scrollPosition : UITableViewScrollPositionNone ] ;
2012-06-18 16:45:36 -07:00
// check to see if the cell is completely visible
CGRect cellRect = [ storyTitlesTable rectForRowAtIndexPath : indexPath ] ;
cellRect = [ storyTitlesTable convertRect : cellRect toView : storyTitlesTable . superview ] ;
BOOL completelyVisible = CGRectContainsRect ( storyTitlesTable . frame , cellRect ) ;
if ( ! completelyVisible ) {
2012-06-18 17:20:34 -07:00
[ storyTitlesTable scrollToRowAtIndexPath : offsetIndexPath
atScrollPosition : UITableViewScrollPositionTop
animated : YES ] ;
2012-06-18 16:45:36 -07:00
}
}
2013-10-01 14:19:12 -07:00
# pragma mark -
2013-10-01 15:38:29 -07:00
# pragma mark Story Actions - read
2013-10-01 16:21:23 -07:00
- ( void ) markStoryAsRead : ( NSDictionary * ) story {
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_story_hashes_as_read" ,
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : [ story objectForKey : @ "story_hash" ]
forKey : @ "story_hash" ] ;
[ request setDidFinishSelector : @ selector ( finishMarkAsRead : ) ] ;
[ request setDidFailSelector : @ selector ( failedMarkAsRead : ) ] ;
[ request setDelegate : self ] ;
[ request setUserInfo : story ] ;
[ request startAsynchronous ] ;
2013-10-17 17:23:52 -07:00
if ( [ appDelegate . dictFeeds objectForKey : [ NSString stringWithFormat : @ "%@" , [ story objectForKey : @ "story_feed_id" ] ] ] ) {
[ appDelegate markStoryRead : [ story objectForKey : @ "story_hash" ]
feedId : [ story objectForKey : @ "story_feed_id" ] ] ;
}
2013-10-01 16:21:23 -07:00
}
- ( void ) finishMarkAsRead : ( ASIFormDataRequest * ) request {
if ( [ request responseStatusCode ] ! = 200 ) {
return [ self failedMarkAsRead : request ] ;
}
[ appDelegate . storyPageControl refreshHeaders ] ;
}
- ( void ) failedMarkAsRead : ( ASIFormDataRequest * ) request {
NSString * storyFeedId = [ request . userInfo objectForKey : @ "story_feed_id" ] ;
NSString * storyHash = [ request . userInfo objectForKey : @ "story_hash" ] ;
[ appDelegate queueReadStories : @ { storyFeedId : @ [ storyHash ] } ] ;
}
- ( void ) markStoryAsUnread : ( NSDictionary * ) story {
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_story_as_unread" ,
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : [ story objectForKey : @ "story_hash" ]
forKey : @ "story_id" ] ;
[ request setPostValue : [ story objectForKey : @ "story_feed_id" ]
forKey : @ "feed_id" ] ;
[ request setDidFinishSelector : @ selector ( finishMarkAsUnread : ) ] ;
[ request setDidFailSelector : @ selector ( failedMarkAsUnread : ) ] ;
[ request setDelegate : self ] ;
[ request setUserInfo : story ] ;
[ request startAsynchronous ] ;
[ appDelegate markStoryUnread : [ story objectForKey : @ "story_hash" ]
feedId : [ story objectForKey : @ "story_feed_id" ] ] ;
}
- ( void ) finishMarkAsUnread : ( ASIFormDataRequest * ) request {
2013-10-01 19:32:40 -07:00
NSString * responseString = [ request responseString ] ;
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
if ( [ request responseStatusCode ] ! = 200 || [ [ results objectForKey : @ "code" ] integerValue ] < 0 ) {
2013-10-01 16:21:23 -07:00
return [ self failedMarkAsUnread : request ] ;
}
2013-10-07 10:02:44 -07:00
appDelegate . storyPageControl . currentPage . isRecentlyUnread = YES ;
2013-10-01 16:21:23 -07:00
[ appDelegate . storyPageControl refreshHeaders ] ;
}
- ( void ) failedMarkAsUnread : ( ASIFormDataRequest * ) request {
2013-10-03 18:07:39 -07:00
NSString * storyFeedId = [ request . userInfo objectForKey : @ "story_feed_id" ] ;
NSString * storyHash = [ request . userInfo objectForKey : @ "story_hash" ] ;
BOOL dequeued = [ appDelegate dequeueReadStoryHash : storyHash inFeed : storyFeedId ] ;
if ( ! dequeued ) {
[ self informError : @ "Failed to unread story" ] ;
[ appDelegate markStoryRead : storyHash feedId : storyFeedId ] ;
[ self . storyTitlesTable reloadData ] ;
} else {
[ appDelegate . unreadStoryHashes setObject : [ NSNumber numberWithBool : YES ] forKey : storyHash ] ;
[ self . storyTitlesTable reloadData ] ;
}
2013-10-01 16:21:23 -07:00
}
2013-10-01 15:38:29 -07:00
# pragma mark -
# pragma mark Story Actions - save
2013-10-01 14:19:12 -07:00
- ( void ) markStoryAsSaved : ( NSDictionary * ) story {
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_story_as_starred" ,
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : [ story objectForKey : @ "story_hash" ]
forKey : @ "story_id" ] ;
[ request setPostValue : [ story objectForKey : @ "story_feed_id" ]
forKey : @ "feed_id" ] ;
[ request setDidFinishSelector : @ selector ( finishMarkAsSaved : ) ] ;
[ request setDidFailSelector : @ selector ( failedMarkAsSaved : ) ] ;
[ request setDelegate : self ] ;
[ request setUserInfo : story ] ;
[ request startAsynchronous ] ;
[ appDelegate markStory : story asSaved : YES ] ;
}
- ( void ) finishMarkAsSaved : ( ASIFormDataRequest * ) request {
if ( [ request responseStatusCode ] ! = 200 ) {
return [ self failedMarkAsSaved : request ] ;
}
[ appDelegate . storyPageControl refreshHeaders ] ;
}
- ( void ) failedMarkAsSaved : ( ASIFormDataRequest * ) request {
[ self informError : @ "Failed to save story" ] ;
[ appDelegate markStory : request . userInfo asSaved : NO ] ;
[ self . storyTitlesTable reloadData ] ;
}
- ( void ) markStoryAsUnsaved : ( NSDictionary * ) story {
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_story_as_unstarred" ,
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : [ story objectForKey : @ "story_hash" ]
forKey : @ "story_id" ] ;
[ request setPostValue : [ story objectForKey : @ "story_feed_id" ]
forKey : @ "feed_id" ] ;
[ request setDidFinishSelector : @ selector ( finishMarkAsUnsaved : ) ] ;
[ request setDidFailSelector : @ selector ( failedMarkAsUnsaved : ) ] ;
[ request setDelegate : self ] ;
[ request setUserInfo : story ] ;
[ request startAsynchronous ] ;
[ appDelegate markStory : story asSaved : NO ] ;
}
- ( void ) finishMarkAsUnsaved : ( ASIFormDataRequest * ) request {
if ( [ request responseStatusCode ] ! = 200 ) {
return [ self failedMarkAsUnsaved : request ] ;
}
[ appDelegate . storyPageControl refreshHeaders ] ;
}
- ( void ) failedMarkAsUnsaved : ( ASIFormDataRequest * ) request {
[ self informError : @ "Failed to unsave story" ] ;
[ appDelegate markStory : request . userInfo asSaved : YES ] ;
[ self . storyTitlesTable reloadData ] ;
}
2011-08-18 09:56:52 -07:00
2012-06-22 18:33:44 -07:00
# pragma mark -
# pragma mark instafetchFeed
// called when the user taps refresh button
2012-06-27 15:38:51 -07:00
- ( void ) instafetchFeed {
2013-01-07 16:34:59 -08:00
NSString * urlString = [ NSString
2013-06-18 21:23:20 -04:00
stringWithFormat : @ "%@/reader/refresh_feed/%@" ,
2012-06-22 18:33:44 -07:00
NEWSBLUR_URL ,
[ appDelegate . activeFeed objectForKey : @ "id" ] ] ;
[ self cancelRequests ] ;
2013-06-04 18:02:05 -07:00
ASIHTTPRequest * request = [ self requestWithURL : urlString ] ;
2012-06-22 18:33:44 -07:00
[ request setDelegate : self ] ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDidFinishSelector : @ selector ( finishedRefreshingFeed : ) ] ;
[ request setDidFailSelector : @ selector ( failRefreshingFeed : ) ] ;
[ request setTimeOutSeconds : 60 ] ;
[ request startAsynchronous ] ;
[ appDelegate setStories : nil ] ;
self . feedPage = 1 ;
self . pageFetching = YES ;
[ self . storyTitlesTable reloadData ] ;
[ storyTitlesTable scrollRectToVisible : CGRectMake ( 0 , 0 , 1 , 1 ) animated : YES ] ;
}
- ( void ) finishedRefreshingFeed : ( ASIHTTPRequest * ) request {
NSString * responseString = [ request responseString ] ;
2012-07-27 16:21:44 -07:00
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
2012-07-16 19:45:14 -07:00
2012-06-22 18:33:44 -07:00
[ self renderStories : [ results objectForKey : @ "stories" ] ] ;
}
- ( void ) failRefreshingFeed : ( ASIHTTPRequest * ) request {
NSLog ( @ "Fail: %@" , request ) ;
[ self informError : [ request error ] ] ;
[ self fetchFeedDetail : 1 withCallback : nil ] ;
}
2012-06-29 10:20:06 -07:00
# pragma mark -
# pragma mark loadSocial Feeds
- ( void ) loadFaviconsFromActiveFeed {
NSArray * keys = [ appDelegate . dictActiveFeeds allKeys ] ;
2012-07-20 15:54:10 -07:00
if ( ! [ keys count ] ) {
// if no new favicons , return
return ;
}
2012-06-29 10:20:06 -07:00
NSString * feedIdsQuery = [ NSString stringWithFormat : @ "?feed_ids=%@" ,
[ [ keys valueForKey : @ "description" ] componentsJoinedByString : @ "&feed_ids=" ] ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/favicons%@" ,
2012-06-29 10:20:06 -07:00
NEWSBLUR_URL ,
feedIdsQuery ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
ASIHTTPRequest * request = [ ASIHTTPRequest requestWithURL : url ] ;
[ request setDidFinishSelector : @ selector ( saveAndDrawFavicons : ) ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
[ request setDelegate : self ] ;
[ request startAsynchronous ] ;
}
- ( void ) saveAndDrawFavicons : ( ASIHTTPRequest * ) request {
NSString * responseString = [ request responseString ] ;
2012-07-27 16:21:44 -07:00
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
2012-06-29 10:20:06 -07:00
dispatch_queue _t queue = dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _HIGH , 0 ul ) ;
dispatch_async ( queue , ^ {
for ( id feed_id in results ) {
2012-07-27 16:21:44 -07:00
NSMutableDictionary * feed = [ [ appDelegate . dictActiveFeeds objectForKey : feed_id ] mutableCopy ] ;
2012-06-29 10:20:06 -07:00
[ feed setValue : [ results objectForKey : feed_id ] forKey : @ "favicon" ] ;
[ appDelegate . dictActiveFeeds setValue : feed forKey : feed_id ] ;
NSString * favicon = [ feed objectForKey : @ "favicon" ] ;
if ( ( NSNull * ) favicon ! = [ NSNull null ] && [ favicon length ] > 0 ) {
NSData * imageData = [ NSData dataWithBase64EncodedString : favicon ] ;
UIImage * faviconImage = [ UIImage imageWithData : imageData ] ;
[ Utilities saveImage : faviconImage feedId : feed_id ] ;
}
}
[ Utilities saveimagesToDisk ] ;
dispatch_sync ( dispatch_get _main _queue ( ) , ^ {
[ self . storyTitlesTable reloadData ] ;
} ) ;
} ) ;
}
- ( void ) requestFailed : ( ASIHTTPRequest * ) request {
NSError * error = [ request error ] ;
NSLog ( @ "Error: %@" , error ) ;
2013-03-06 14:29:40 -08:00
[ appDelegate informError : error ] ;
2012-06-29 10:20:06 -07:00
}
2012-10-12 13:58:26 -04:00
# pragma mark -
# pragma mark WEPopoverControllerDelegate implementation
- ( void ) popoverControllerDidDismissPopover : ( WEPopoverController * ) thePopoverController {
// Safe to release the popover here
self . popoverController = nil ;
}
- ( BOOL ) popoverControllerShouldDismissPopover : ( WEPopoverController * ) thePopoverController {
// The popover is automatically dismissed if you click outside it , unless you return NO here
return YES ;
}
- ( WEPopoverContainerViewProperties * ) improvedContainerViewProperties {
WEPopoverContainerViewProperties * props = [ WEPopoverContainerViewProperties alloc ] ;
NSString * bgImageName = nil ;
CGFloat bgMargin = 0.0 ;
CGFloat bgCapSize = 0.0 ;
CGFloat contentMargin = 5.0 ;
bgImageName = @ "popoverBg.png" ;
// These constants are determined by the popoverBg . png image file and are image dependent
bgMargin = 13 ; // margin width of 13 pixels on all sides popoverBg . png ( 62 pixels wide - 36 pixel background ) / 2 = = 26 / 2 = = 13
bgCapSize = 31 ; // ImageSize / 2 = = 62 / 2 = = 31 pixels
props . leftBgMargin = bgMargin ;
props . rightBgMargin = bgMargin ;
props . topBgMargin = bgMargin ;
props . bottomBgMargin = bgMargin ;
props . leftBgCapSize = bgCapSize ;
props . topBgCapSize = bgCapSize ;
props . bgImageName = bgImageName ;
props . leftContentMargin = contentMargin ;
props . rightContentMargin = contentMargin - 1 ; // Need to shift one pixel for border to look correct
props . topContentMargin = contentMargin ;
props . bottomContentMargin = contentMargin ;
props . arrowMargin = 4.0 ;
props . upArrowImageName = @ "popoverArrowUp.png" ;
props . downArrowImageName = @ "popoverArrowDown.png" ;
props . leftArrowImageName = @ "popoverArrowLeft.png" ;
props . rightArrowImageName = @ "popoverArrowRight.png" ;
return props ;
}
2010-06-21 17:17:26 -04:00
@ end