2010-06-17 13:10:45 -04:00
//
// NewsBlurAppDelegate . m
// NewsBlur
//
// Created by Samuel Clay on 6 / 16 / 10.
2010-06-21 17:17:26 -04:00
// Copyright NewsBlur 2010. All rights reserved .
2010-06-17 13:10:45 -04:00
//
# import "NewsBlurAppDelegate.h"
2012-06-19 11:48:51 -07:00
# import "NewsBlurViewController.h"
2012-07-24 11:44:16 -07:00
# import "NBContainerViewController.h"
2010-06-21 17:17:26 -04:00
# import "FeedDetailViewController.h"
2012-07-15 15:06:06 -07:00
# import "DashboardViewController.h"
2012-06-19 10:55:46 -07:00
# import "FeedsMenuViewController.h"
2012-10-12 13:58:26 -04:00
# import "FeedDetailMenuViewController.h"
2010-06-25 18:36:01 -04:00
# import "StoryDetailViewController.h"
2012-11-05 15:12:42 -08:00
# import "StoryPageControl.h"
2012-06-13 18:07:24 -07:00
# import "FirstTimeUserViewController.h"
2012-08-12 18:50:32 -07:00
# import "FriendsListViewController.h"
2010-10-31 23:02:13 -04:00
# import "LoginViewController.h"
2011-12-02 16:23:00 -08:00
# import "AddSiteViewController.h"
# import "MoveSiteViewController.h"
2012-12-24 23:01:25 -08:00
# import "TrainerViewController.h"
2010-11-13 18:32:43 -05:00
# import "OriginalStoryViewController.h"
2012-06-21 11:53:48 -07:00
# import "ShareViewController.h"
2012-07-01 18:26:39 -07:00
# import "UserProfileViewController.h"
2012-07-24 16:03:16 -07:00
# import "NBContainerViewController.h"
2012-07-28 23:31:12 -07:00
# import "AFJSONRequestOperation.h"
2013-06-22 19:34:12 -07:00
# import "ASINetworkQueue.h"
2012-08-14 17:20:45 -07:00
# import "InteractionsModule.h"
# import "ActivityModule.h"
2012-08-15 13:04:05 -07:00
# import "FirstTimeUserViewController.h"
# import "FirstTimeUserAddSitesViewController.h"
# import "FirstTimeUserAddFriendsViewController.h"
# import "FirstTimeUserAddNewsBlurViewController.h"
2011-10-27 09:44:58 -07:00
# import "MBProgressHUD.h"
2011-10-28 18:29:33 -07:00
# import "Utilities.h"
2011-12-04 21:09:16 -08:00
# import "StringHelper.h"
2013-03-04 20:21:29 -08:00
# import "AuthorizeServicesViewController.h"
2013-03-06 16:23:17 -08:00
# import "ShareThis.h"
2013-05-30 18:45:51 -07:00
# import "Reachability.h"
2013-06-05 17:11:01 -07:00
# import "FMDatabase.h"
2013-06-14 19:21:30 -07:00
# import "FMDatabaseQueue.h"
2013-06-16 21:39:38 -07:00
# import "FMDatabaseAdditions.h"
2013-06-15 17:33:31 -07:00
# import "JSON.h"
2013-06-21 17:48:06 -07:00
# import "IASKAppSettingsViewController.h"
2010-06-17 13:10:45 -04:00
@ implementation NewsBlurAppDelegate
2013-06-29 17:28:41 -07:00
# define CURRENT_DB _VERSION 23
2012-11-01 15:26:50 -07:00
# define IS_IPHONE _5 ( fabs ( ( double ) [ [ UIScreen mainScreen ] bounds ] . size . height - ( double ) 568 ) < DBL_EPSILON )
2010-06-17 13:10:45 -04:00
@ synthesize window ;
2012-06-09 12:54:32 -07:00
2012-07-22 14:23:50 -07:00
@ synthesize ftuxNavigationController ;
2010-06-21 17:17:26 -04:00
@ synthesize navigationController ;
2012-07-31 17:17:02 -07:00
@ synthesize modalNavigationController ;
2012-08-13 18:45:06 -07:00
@ synthesize shareNavigationController ;
2013-03-02 19:15:08 -08:00
@ synthesize trainNavigationController ;
2012-07-28 12:56:51 -07:00
@ synthesize userProfileNavigationController ;
2012-07-24 11:44:16 -07:00
@ synthesize masterContainerViewController ;
2012-07-10 12:34:58 -07:00
@ synthesize dashboardViewController ;
2010-06-21 17:17:26 -04:00
@ synthesize feedsViewController ;
2012-06-19 10:55:46 -07:00
@ synthesize feedsMenuViewController ;
2010-06-24 12:53:50 -04:00
@ synthesize feedDetailViewController ;
2012-10-12 13:58:26 -04:00
@ synthesize feedDetailMenuViewController ;
2012-06-20 09:32:55 -07:00
@ synthesize feedDashboardViewController ;
2012-07-01 18:26:39 -07:00
@ synthesize friendsListViewController ;
2012-06-18 14:31:42 -07:00
@ synthesize fontSettingsViewController ;
2010-06-25 18:36:01 -04:00
@ synthesize storyDetailViewController ;
2012-11-05 15:12:42 -08:00
@ synthesize storyPageControl ;
2012-06-22 18:01:08 -07:00
@ synthesize shareViewController ;
2010-10-31 23:02:13 -04:00
@ synthesize loginViewController ;
2011-12-02 16:23:00 -08:00
@ synthesize addSiteViewController ;
@ synthesize moveSiteViewController ;
2012-12-24 23:01:25 -08:00
@ synthesize trainerViewController ;
2010-11-13 18:32:43 -05:00
@ synthesize originalStoryViewController ;
2012-07-01 18:26:39 -07:00
@ synthesize userProfileViewController ;
2013-06-21 17:48:06 -07:00
@ synthesize preferencesViewController ;
2010-06-17 13:10:45 -04:00
2012-07-22 14:23:50 -07:00
@ synthesize firstTimeUserViewController ;
@ synthesize firstTimeUserAddSitesViewController ;
@ synthesize firstTimeUserAddFriendsViewController ;
@ synthesize firstTimeUserAddNewsBlurViewController ;
2012-06-20 08:33:16 -07:00
@ synthesize feedDetailPortraitYCoordinate ;
2010-11-13 18:32:43 -05:00
@ synthesize activeUsername ;
2012-07-03 17:54:36 -07:00
@ synthesize activeUserProfileId ;
2012-07-28 14:15:20 -07:00
@ synthesize activeUserProfileName ;
2012-10-02 15:39:18 -07:00
@ synthesize hasNoSites ;
2011-10-25 09:28:05 -07:00
@ synthesize isRiverView ;
2012-06-26 11:45:42 -07:00
@ synthesize isSocialView ;
2012-08-08 10:57:38 -07:00
@ synthesize isSocialRiverView ;
2012-08-06 19:21:39 -07:00
@ synthesize isTryFeedView ;
2012-08-02 18:00:48 -07:00
2012-07-16 22:35:28 -07:00
@ synthesize inFindingStoryMode ;
2013-06-16 08:15:40 -07:00
@ synthesize hasQueuedReadStories ;
2012-07-16 19:45:14 -07:00
@ synthesize tryFeedStoryId ;
2012-07-31 23:49:51 -07:00
@ synthesize tryFeedCategory ;
2012-06-19 15:47:51 -07:00
@ synthesize popoverHasFeedView ;
2012-06-29 23:25:56 -07:00
@ synthesize inFeedDetail ;
2012-08-02 18:00:48 -07:00
@ synthesize inStoryDetail ;
2012-06-25 18:05:25 -07:00
@ synthesize activeComment ;
2012-07-27 12:27:13 -07:00
@ synthesize activeShareType ;
2010-06-25 18:36:01 -04:00
@ synthesize activeFeed ;
2012-12-07 16:17:48 -08:00
@ synthesize activeClassifiers ;
2012-12-27 00:15:26 -08:00
@ synthesize activePopularTags ;
@ synthesize activePopularAuthors ;
2011-10-20 09:32:39 -07:00
@ synthesize activeFolder ;
2011-10-26 08:40:31 -07:00
@ synthesize activeFolderFeeds ;
2010-06-25 18:36:01 -04:00
@ synthesize activeFeedStories ;
2011-07-29 21:27:37 -07:00
@ synthesize activeFeedStoryLocations ;
2011-08-08 09:58:15 -07:00
@ synthesize activeFeedStoryLocationIds ;
2012-06-22 18:01:08 -07:00
@ synthesize activeFeedUserProfiles ;
2010-06-25 18:36:01 -04:00
@ synthesize activeStory ;
2011-07-24 16:52:24 -07:00
@ synthesize storyCount ;
2012-11-26 09:54:20 -08:00
@ synthesize storyLocationsCount ;
2011-11-09 09:51:42 -08:00
@ synthesize visibleUnreadCount ;
2012-10-17 15:07:53 -07:00
@ synthesize savedStoriesCount ;
2013-06-16 14:09:28 -07:00
@ synthesize totalUnfetchedStoryCount ;
2013-06-16 21:39:38 -07:00
@ synthesize remainingUnfetchedStoryCount ;
@ synthesize latestFetchedStoryDate ;
2013-06-21 22:18:54 -07:00
@ synthesize totalUncachedImagesCount ;
@ synthesize remainingUncachedImagesCount ;
2011-08-09 17:58:43 -07:00
@ synthesize originalStoryCount ;
2011-07-29 09:06:17 -07:00
@ synthesize selectedIntelligence ;
2010-11-13 18:32:43 -05:00
@ synthesize activeOriginalStoryURL ;
2011-07-24 21:47:58 -07:00
@ synthesize recentlyReadStories ;
2011-11-03 18:08:24 -07:00
@ synthesize recentlyReadFeeds ;
2011-08-22 18:25:33 -07:00
@ synthesize readStories ;
2012-10-14 17:30:03 -07:00
@ synthesize folderCountCache ;
2010-06-17 13:10:45 -04:00
2011-10-04 18:01:35 -07:00
@ synthesize dictFolders ;
@ synthesize dictFeeds ;
2012-06-26 16:24:19 -07:00
@ synthesize dictActiveFeeds ;
2012-06-25 15:02:20 -07:00
@ synthesize dictSocialFeeds ;
2013-03-04 20:21:29 -08:00
@ synthesize dictSocialProfile ;
2012-07-01 18:26:39 -07:00
@ synthesize dictUserProfile ;
2013-03-04 20:21:29 -08:00
@ synthesize dictSocialServices ;
2013-06-29 17:28:41 -07:00
@ synthesize dictUnreadCounts ;
2012-07-26 23:07:47 -07:00
@ synthesize userInteractionsArray ;
@ synthesize userActivitiesArray ;
2011-10-04 18:01:35 -07:00
@ synthesize dictFoldersArray ;
2013-06-05 17:11:01 -07:00
@ synthesize database ;
2012-08-14 17:20:45 -07:00
@ synthesize categories ;
@ synthesize categoryFeeds ;
2013-06-22 19:34:12 -07:00
@ synthesize operationQueue ;
2013-06-23 22:19:08 -07:00
@ synthesize activeCachedImages ;
2012-08-14 17:20:45 -07:00
2011-12-03 18:22:14 -08:00
+ ( NewsBlurAppDelegate * ) sharedAppDelegate {
return ( NewsBlurAppDelegate * ) [ UIApplication sharedApplication ] . delegate ;
}
2010-06-17 13:10:45 -04:00
- ( BOOL ) application : ( UIApplication * ) application didFinishLaunchingWithOptions : ( NSDictionary * ) launchOptions {
2012-06-30 00:02:08 -07:00
NSString * currentiPhoneVersion = [ [ [ NSBundle mainBundle ] infoDictionary ] objectForKey : @ "CFBundleVersion" ] ;
2013-03-03 14:03:56 -08:00
self . navigationController . delegate = self ;
2012-07-24 16:03:16 -07:00
self . navigationController . viewControllers = [ NSArray arrayWithObject : self . feedsViewController ] ;
2012-06-30 00:02:08 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
[ ASIHTTPRequest setDefaultUserAgentString : [ NSString stringWithFormat : @ "NewsBlur iPad App v%@" ,
currentiPhoneVersion ] ] ;
2012-07-24 11:44:16 -07:00
[ window addSubview : self . masterContainerViewController . view ] ;
self . window . rootViewController = self . masterContainerViewController ;
2012-06-09 12:54:32 -07:00
} else {
2012-07-24 16:03:16 -07:00
[ ASIHTTPRequest setDefaultUserAgentString : [ NSString stringWithFormat : @ "NewsBlur iPhone App v%@" ,
currentiPhoneVersion ] ] ;
2012-07-01 12:08:30 -07:00
[ window addSubview : self . navigationController . view ] ;
2012-07-24 16:03:16 -07:00
self . window . rootViewController = self . navigationController ;
2012-06-09 12:54:32 -07:00
}
2013-04-12 10:11:21 -07:00
2010-06-17 13:10:45 -04:00
[ window makeKeyAndVisible ] ;
2012-08-09 10:18:15 -07:00
[ self . feedsViewController fetchFeedList : YES ] ;
2012-06-27 21:28:04 -07:00
2013-05-30 16:31:57 -07:00
[ ShareThis startSessionWithFacebookURLSchemeSuffix : @ "newsblur" pocketAPI : @ "c23d9HbTT2a8fma098AfIr9zQTgcF0l9" readabilityKey : @ "samuelclay" readabilitySecret : @ "ktLQc88S9WCE8PfvZ4u4q995Q3HMzg6Q" ] ;
[ [ UINavigationBar appearance ]
setBackgroundImage : [ UIImage imageNamed : @ "navbar_background.png" ]
forBarMetrics : UIBarMetricsDefault ] ;
[ [ UINavigationBar appearance ]
setBackgroundImage : [ UIImage imageNamed : @ "navbar_landscape_background.png" ]
forBarMetrics : UIBarMetricsLandscapePhone ] ;
[ [ UIToolbar appearance ]
setBackgroundImage : [ UIImage imageNamed : @ "toolbar_background.png" ]
forToolbarPosition : UIToolbarPositionBottom barMetrics : UIBarMetricsDefault ] ;
[ [ UIToolbar appearance ]
setBackgroundImage : [ UIImage imageNamed : @ "navbar_background.png" ]
forToolbarPosition : UIToolbarPositionTop barMetrics : UIBarMetricsDefault ] ;
[ [ UIToolbar appearance ]
setBackgroundImage : [ UIImage imageNamed : @ "navbar_landscape_background.png" ]
forToolbarPosition : UIToolbarPositionAny barMetrics : UIBarMetricsLandscapePhone ] ;
[ [ UINavigationBar appearance ]
setTitleTextAttributes : [ NSDictionary dictionaryWithObjectsAndKeys :
UIColorFromRGB ( 0 x404040 ) , UITextAttributeTextColor ,
UIColorFromRGB ( 0 xFAFAFA ) , UITextAttributeTextShadowColor ,
[ NSValue valueWithUIOffset : UIOffsetMake ( 0 , -1 ) ] ,
UITextAttributeTextShadowOffset ,
nil ] ] ;
[ self performSelectorOnMainThread : @ selector ( showSplashView ) withObject : nil waitUntilDone : NO ] ;
2013-06-14 19:21:30 -07:00
[ self createDatabaseConnection ] ;
2013-05-30 16:31:57 -07:00
// [ self showFirstTimeUser ] ;
2013-05-30 19:23:10 -07:00
2013-05-30 16:31:57 -07:00
return YES ;
}
- ( void ) showSplashView {
2012-11-08 17:39:32 -08:00
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
2012-11-01 15:26:50 -07:00
splashView = [ [ UIImageView alloc ] init ] ;
2013-05-30 18:45:51 -07:00
// int rotate = 0 ;
// if ( orientation = = UIInterfaceOrientationPortraitUpsideDown ) {
// NSLog ( @ "UPSIDE DOWN" ) ;
// rotate = -2 ;
// } else if ( orientation = = UIInterfaceOrientationLandscapeLeft ) {
// rotate = -1 ;
// } else if ( orientation = = UIInterfaceOrientationLandscapeRight ) {
// rotate = 1 ;
// }
// splashView . transform = CGAffineTransformMakeRotation ( M_PI * rotate * 90.0 / 180 ) ;
2012-11-08 17:39:32 -08:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad &&
UIInterfaceOrientationIsLandscape ( orientation ) ) {
2013-05-30 16:31:57 -07:00
splashView . frame = CGRectMake ( 0 , 0 , self . view . frame . size . height , self . view . frame . size . width ) ;
2012-11-08 17:39:32 -08:00
splashView . image = [ UIImage imageNamed : @ "Default-Landscape.png" ] ;
2013-05-30 16:31:57 -07:00
NSLog ( @ "Window frame; %@" , NSStringFromCGRect ( self . view . frame ) ) ;
2012-11-08 17:39:32 -08:00
} else if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-11-01 15:26:50 -07:00
splashView . frame = self . view . frame ;
splashView . image = [ UIImage imageNamed : @ "Default-Portrait.png" ] ;
} else if ( IS_IPHONE _5 ) {
2013-04-12 10:11:21 -07:00
splashView . frame = CGRectMake ( 0 , 0 , self . window . frame . size . width , 568 ) ;
2012-11-01 15:26:50 -07:00
splashView . image = [ UIImage imageNamed : @ "Default-568h.png" ] ;
} else {
splashView . frame = self . window . frame ;
splashView . image = [ UIImage imageNamed : @ "Default.png" ] ;
}
2012-11-08 17:39:32 -08:00
2013-05-30 16:31:57 -07:00
// [ splashView setAutoresizingMask : UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ] ;
2012-12-27 23:04:25 -08:00
splashView . alpha = 1.0 ;
2013-04-12 10:11:21 -07:00
[ window . rootViewController . view addSubview : splashView ] ;
2012-11-01 15:26:50 -07:00
[ UIView beginAnimations : nil context : nil ] ;
2012-12-27 23:04:25 -08:00
[ UIView setAnimationDuration : .6 ] ;
2012-11-01 15:26:50 -07:00
[ UIView setAnimationTransition : UIViewAnimationTransitionNone forView : window cache : YES ] ;
[ UIView setAnimationDelegate : self ] ;
[ UIView setAnimationDidStopSelector : @ selector ( startupAnimationDone : finished : context : ) ] ;
2013-05-30 16:31:57 -07:00
// splashView . alpha = 0 ;
2013-04-12 10:11:21 -07:00
splashView . frame = CGRectMake ( 0 , -1 * splashView . frame . size . height , splashView . frame . size . width , splashView . frame . size . height ) ;
// splashView . frame = CGRectMake ( -60 , -80 , 440 , 728 ) ;
2012-11-01 15:26:50 -07:00
[ UIView commitAnimations ] ;
2013-05-30 18:45:51 -07:00
[ self setupReachability ] ;
2010-06-17 13:10:45 -04:00
}
2010-11-11 20:05:53 -05:00
2011-07-29 09:06:17 -07:00
- ( void ) viewDidLoad {
2011-11-09 09:51:42 -08:00
self . visibleUnreadCount = 0 ;
2012-10-17 15:07:53 -07:00
self . savedStoriesCount = 0 ;
2013-06-16 14:09:28 -07:00
self . totalUnfetchedStoryCount = 0 ;
2013-06-16 21:39:38 -07:00
self . remainingUnfetchedStoryCount = 0 ;
self . latestFetchedStoryDate = 0 ;
2013-06-21 22:18:54 -07:00
self . totalUncachedImagesCount = 0 ;
self . remainingUncachedImagesCount = 0 ;
2011-08-01 09:43:13 -07:00
[ self setRecentlyReadStories : [ NSMutableArray array ] ] ;
2011-07-29 09:06:17 -07:00
}
2012-11-01 15:26:50 -07:00
- ( void ) startupAnimationDone : ( NSString * ) animationID finished : ( NSNumber * ) finished context : ( void * ) context {
[ splashView removeFromSuperview ] ;
}
2013-03-06 16:23:17 -08:00
- ( void ) applicationDidBecomeActive : ( UIApplication * ) application {
[ [ NSNotificationCenter defaultCenter ] postNotificationName : AppDidBecomeActiveNotificationName object : nil ] ;
}
- ( void ) applicationWillTerminate : ( UIApplication * ) application {
[ [ NSNotificationCenter defaultCenter ] postNotificationName : AppWillTerminateNotificationName object : nil ] ;
}
- ( BOOL ) application : ( UIApplication * ) application openURL : ( NSURL * ) url sourceApplication : ( NSString * ) sourceApplication annotation : ( id ) annotation {
return [ ShareThis handleFacebookOpenUrl : url ] ;
}
2013-05-30 18:45:51 -07:00
- ( void ) setupReachability {
2013-06-18 21:23:20 -04:00
Reachability * reach = [ Reachability reachabilityWithHostname : NEWSBLUR_HOST ] ;
2013-05-30 18:45:51 -07:00
[ [ NSNotificationCenter defaultCenter ] addObserver : self
selector : @ selector ( reachabilityChanged : )
name : kReachabilityChangedNotification
object : nil ] ;
reach . reachableBlock = ^ ( Reachability * reach ) {
NSLog ( @ "Reachable: %@" , reach ) ;
} ;
reach . unreachableBlock = ^ ( Reachability * reach ) {
NSLog ( @ "Un-Reachable: %@" , reach ) ;
} ;
[ reach startNotifier ] ;
}
- ( void ) reachabilityChanged : ( id ) something {
NSLog ( @ "Reachability changed: %@" , something ) ;
}
2013-03-06 16:23:17 -08:00
2012-06-29 23:48:47 -07:00
# pragma mark -
2012-07-01 12:08:30 -07:00
# pragma mark Social Views
2012-07-28 12:56:51 -07:00
- ( void ) showUserProfileModal : ( id ) sender {
2012-08-02 18:00:48 -07:00
UserProfileViewController * newUserProfile = [ [ UserProfileViewController alloc ] init ] ;
self . userProfileViewController = newUserProfile ;
2012-07-12 22:05:23 -07:00
UINavigationController * navController = [ [ UINavigationController alloc ] initWithRootViewController : self . userProfileViewController ] ;
2012-07-28 12:56:51 -07:00
self . userProfileNavigationController = navController ;
2012-07-31 00:53:16 -07:00
2012-07-28 12:56:51 -07:00
// adding Done button
UIBarButtonItem * donebutton = [ [ UIBarButtonItem alloc ]
2012-07-28 14:56:40 -07:00
initWithTitle : @ "Close"
2012-07-28 12:56:51 -07:00
style : UIBarButtonItemStyleDone
target : self
action : @ selector ( hideUserProfileModal ) ] ;
2012-08-02 18:00:48 -07:00
newUserProfile . navigationItem . rightBarButtonItem = donebutton ;
newUserProfile . navigationItem . title = self . activeUserProfileName ;
newUserProfile . navigationItem . backBarButtonItem . title = self . activeUserProfileName ;
[ newUserProfile getUserProfile ] ;
2012-07-25 17:29:29 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-28 12:56:51 -07:00
[ self . masterContainerViewController showUserProfilePopover : sender ] ;
2012-07-25 17:29:29 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ self . navigationController presentViewController : navController animated : YES completion : nil ] ;
2012-07-25 17:29:29 -07:00
}
2012-07-31 23:49:51 -07:00
2012-07-12 22:05:23 -07:00
}
2012-07-28 14:15:20 -07:00
- ( void ) pushUserProfile {
UserProfileViewController * userProfileView = [ [ UserProfileViewController alloc ] init ] ;
// adding Done button
UIBarButtonItem * donebutton = [ [ UIBarButtonItem alloc ]
2012-07-28 14:56:40 -07:00
initWithTitle : @ "Close"
2012-07-28 14:15:20 -07:00
style : UIBarButtonItemStyleDone
target : self
action : @ selector ( hideUserProfileModal ) ] ;
userProfileView . navigationItem . rightBarButtonItem = donebutton ;
userProfileView . navigationItem . title = self . activeUserProfileName ;
userProfileView . navigationItem . backBarButtonItem . title = self . activeUserProfileName ;
2012-07-31 10:24:38 -07:00
[ userProfileView getUserProfile ] ;
2012-08-13 23:35:11 -07:00
if ( self . modalNavigationController . view . window = = nil ) {
[ self . userProfileNavigationController pushViewController : userProfileView animated : YES ] ;
} else {
[ self . modalNavigationController pushViewController : userProfileView animated : YES ] ;
} ;
2012-07-28 14:15:20 -07:00
}
2012-07-12 22:05:23 -07:00
- ( void ) hideUserProfileModal {
2012-07-28 12:56:51 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-31 13:10:26 -07:00
[ self . masterContainerViewController hidePopover ] ;
2012-07-28 12:56:51 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ self . navigationController dismissViewControllerAnimated : YES completion : nil ] ;
2012-07-28 12:56:51 -07:00
}
2012-07-12 22:05:23 -07:00
}
2013-06-21 17:48:06 -07:00
- ( void ) showPreferences {
if ( ! preferencesViewController ) {
preferencesViewController = [ [ IASKAppSettingsViewController alloc ] init ] ;
}
preferencesViewController . delegate = self . feedsViewController ;
preferencesViewController . showDoneButton = YES ;
preferencesViewController . showCreditsFooter = NO ;
preferencesViewController . title = @ "Preferences" ;
BOOL enabled = [ [ NSUserDefaults standardUserDefaults ] boolForKey : @ "offline_allowed" ] ;
preferencesViewController . hiddenKeys = enabled ? nil : [ NSSet setWithObjects : @ "offline_image_download" , @ "offline_download_connection" , nil ] ;
UINavigationController * navController = [ [ UINavigationController alloc ] initWithRootViewController : preferencesViewController ] ;
self . modalNavigationController = navController ;
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
self . modalNavigationController . modalPresentationStyle = UIModalPresentationFormSheet ;
[ masterContainerViewController presentViewController : modalNavigationController animated : YES completion : nil ] ;
} else {
[ navigationController presentViewController : modalNavigationController animated : YES completion : nil ] ;
}
}
2012-07-01 12:08:30 -07:00
- ( void ) showFindFriends {
2012-07-31 15:17:51 -07:00
FriendsListViewController * friendsBVC = [ [ FriendsListViewController alloc ] init ] ;
2012-07-31 13:10:26 -07:00
UINavigationController * friendsNav = [ [ UINavigationController alloc ] initWithRootViewController : friendsListViewController ] ;
2013-06-21 17:48:06 -07:00
self . friendsListViewController = friendsBVC ;
2012-07-31 17:17:02 -07:00
self . modalNavigationController = friendsNav ;
2012-07-01 12:08:30 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-31 17:17:02 -07:00
self . modalNavigationController . modalPresentationStyle = UIModalPresentationFormSheet ;
2013-06-17 11:50:13 -07:00
[ masterContainerViewController presentViewController : modalNavigationController animated : YES completion : nil ] ;
2012-07-01 12:08:30 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ navigationController presentViewController : modalNavigationController animated : YES completion : nil ] ;
2012-07-01 12:08:30 -07:00
}
2012-07-31 00:53:16 -07:00
[ self . friendsListViewController loadSuggestedFriendsList ] ;
2012-07-01 12:08:30 -07:00
}
2012-06-29 23:48:47 -07:00
2012-07-20 15:54:10 -07:00
- ( void ) showShareView : ( NSString * ) type
setUserId : ( NSString * ) userId
setUsername : ( NSString * ) username
2012-07-30 14:58:57 -07:00
setReplyId : ( NSString * ) replyId {
2012-07-23 16:17:49 -07:00
2013-03-02 21:27:29 -08:00
[ self . shareViewController setCommentType : type ] ;
2012-07-12 23:44:14 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-25 20:38:44 -07:00
[ self . masterContainerViewController transitionToShareView ] ;
2012-07-12 23:44:14 -07:00
} else {
2012-08-13 18:45:06 -07:00
if ( self . shareNavigationController = = nil ) {
2012-11-28 15:21:44 -08:00
UINavigationController * shareNav = [ [ UINavigationController alloc ]
initWithRootViewController : self . shareViewController ] ;
2012-08-13 18:45:06 -07:00
self . shareNavigationController = shareNav ;
}
2013-03-02 21:27:29 -08:00
[ self . shareViewController setSiteInfo : type setUserId : userId setUsername : username setReplyId : replyId ] ;
2013-06-17 11:50:13 -07:00
[ self . navigationController presentViewController : self . shareNavigationController animated : YES completion : nil ] ;
2012-07-12 23:44:14 -07:00
}
2013-03-02 21:27:29 -08:00
2012-11-28 15:21:44 -08:00
[ self . shareViewController setSiteInfo : type setUserId : userId setUsername : username setReplyId : replyId ] ;
2012-07-12 13:34:41 -07:00
}
- ( void ) hideShareView : ( BOOL ) resetComment {
if ( resetComment ) {
self . shareViewController . commentField . text = @ "" ;
2012-08-13 23:54:10 -07:00
self . shareViewController . currentType = nil ;
2012-07-12 13:34:41 -07:00
}
2012-07-26 11:11:43 -07:00
2012-07-23 16:17:49 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-25 20:38:44 -07:00
[ self . masterContainerViewController transitionFromShareView ] ;
2012-07-12 23:44:14 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ self . navigationController dismissViewControllerAnimated : YES completion : nil ] ;
2012-07-26 11:11:43 -07:00
[ self . shareViewController . commentField resignFirstResponder ] ;
2012-07-12 23:44:14 -07:00
}
2012-06-29 23:48:47 -07:00
}
- ( void ) resetShareComments {
[ shareViewController clearComments ] ;
}
2010-06-24 00:22:26 -04:00
# pragma mark -
2013-06-29 17:28:41 -07:00
# pragma mark View Management
2010-06-24 00:22:26 -04:00
2010-11-11 23:48:27 -05:00
- ( void ) showLogin {
2012-07-01 23:48:43 -07:00
self . dictFeeds = nil ;
self . dictSocialFeeds = nil ;
self . dictFolders = nil ;
self . dictFoldersArray = nil ;
2012-08-14 17:20:45 -07:00
self . userActivitiesArray = nil ;
self . userInteractionsArray = nil ;
2013-06-29 17:28:41 -07:00
self . dictUnreadCounts = nil ;
2012-07-01 23:48:43 -07:00
[ self . feedsViewController . feedTitlesTable reloadData ] ;
2012-08-14 17:20:45 -07:00
[ self . feedsViewController resetToolbar ] ;
[ self . dashboardViewController . interactionsModule . interactionsTable reloadData ] ;
[ self . dashboardViewController . activitiesModule . activitiesTable reloadData ] ;
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
[ userPreferences setInteger : -1 forKey : @ "selectedIntelligence" ] ;
[ userPreferences synchronize ] ;
2012-06-13 12:19:35 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2013-06-17 11:50:13 -07:00
[ self . masterContainerViewController presentViewController : loginViewController animated : NO completion : nil ] ;
2012-06-13 12:19:35 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ feedsMenuViewController dismissViewControllerAnimated : NO completion : nil ] ;
[ self . navigationController presentViewController : loginViewController animated : NO completion : nil ] ;
2012-06-13 12:19:35 -07:00
}
2010-11-11 23:48:27 -05:00
}
2012-06-13 18:07:24 -07:00
- ( void ) showFirstTimeUser {
2012-08-15 13:04:05 -07:00
// [ self . feedsViewController changeToAllMode ] ;
2012-07-22 14:23:50 -07:00
UINavigationController * ftux = [ [ UINavigationController alloc ] initWithRootViewController : self . firstTimeUserViewController ] ;
self . ftuxNavigationController = ftux ;
2012-06-13 18:07:24 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-22 14:23:50 -07:00
self . ftuxNavigationController . modalPresentationStyle = UIModalPresentationFormSheet ;
2013-06-17 11:50:13 -07:00
[ self . masterContainerViewController presentViewController : self . ftuxNavigationController animated : YES completion : nil ] ;
2012-08-14 17:20:45 -07:00
self . ftuxNavigationController . view . superview . frame = CGRectMake ( 0 , 0 , 540 , 540 ) ; // it ' s important to do this after
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
if ( UIInterfaceOrientationIsPortrait ( orientation ) ) {
self . ftuxNavigationController . view . superview . center = self . view . center ;
} else {
self . ftuxNavigationController . view . superview . center = CGPointMake ( self . view . center . y , self . view . center . x ) ;
}
2012-06-13 18:07:24 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ self . navigationController presentViewController : self . ftuxNavigationController animated : YES completion : nil ] ;
2012-06-13 18:07:24 -07:00
}
}
2011-12-02 16:23:00 -08:00
- ( void ) showMoveSite {
UINavigationController * navController = self . navigationController ;
2012-06-08 19:36:23 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
moveSiteViewController . modalPresentationStyle = UIModalPresentationFormSheet ;
2013-06-17 11:50:13 -07:00
[ navController presentViewController : moveSiteViewController animated : YES completion : nil ] ;
2012-06-08 19:36:23 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ navController presentViewController : moveSiteViewController animated : YES completion : nil ] ;
2012-06-08 19:36:23 -07:00
}
2011-10-04 18:01:35 -07:00
}
2012-12-24 23:01:25 -08:00
- ( void ) openTrainSite {
UINavigationController * navController = self . navigationController ;
2012-12-27 00:15:26 -08:00
trainerViewController . feedTrainer = YES ;
trainerViewController . storyTrainer = NO ;
2012-12-24 23:01:25 -08:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-12-27 19:34:05 -08:00
// trainerViewController . modalPresentationStyle = UIModalPresentationFormSheet ;
2013-06-17 11:50:13 -07:00
// [ navController presentViewController : trainerViewController animated : YES completion : nil ] ;
2013-02-27 17:22:49 -08:00
[ self . masterContainerViewController showTrainingPopover : self . feedDetailViewController . settingsBarButton ] ;
2012-12-27 00:15:26 -08:00
} else {
2013-03-02 19:15:08 -08:00
if ( self . trainNavigationController = = nil ) {
self . trainNavigationController = [ [ UINavigationController alloc ]
initWithRootViewController : self . trainerViewController ] ;
}
2013-06-17 11:50:13 -07:00
[ navController presentViewController : self . trainNavigationController animated : YES completion : nil ] ;
2012-12-27 00:15:26 -08:00
}
}
2012-12-27 23:04:25 -08:00
- ( void ) openTrainStory : ( id ) sender {
2012-12-27 00:15:26 -08:00
UINavigationController * navController = self . navigationController ;
trainerViewController . feedTrainer = NO ;
trainerViewController . storyTrainer = YES ;
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-12-27 23:04:25 -08:00
[ self . masterContainerViewController showTrainingPopover : sender ] ;
2012-12-24 23:01:25 -08:00
} else {
2013-03-02 19:15:08 -08:00
if ( self . trainNavigationController = = nil ) {
self . trainNavigationController = [ [ UINavigationController alloc ]
initWithRootViewController : self . trainerViewController ] ;
}
2013-06-17 11:50:13 -07:00
[ navController presentViewController : self . trainNavigationController animated : YES completion : nil ] ;
2012-12-24 23:01:25 -08:00
}
}
2011-12-03 18:22:14 -08:00
- ( void ) reloadFeedsView : ( BOOL ) showLoader {
2012-08-09 10:18:15 -07:00
[ feedsViewController fetchFeedList : showLoader ] ;
2013-06-17 11:50:13 -07:00
[ loginViewController dismissViewControllerAnimated : NO completion : nil ] ;
2010-11-11 20:05:53 -05:00
}
2011-10-06 10:27:37 -07:00
2010-06-25 18:36:01 -04:00
- ( void ) loadFeedDetailView {
2012-06-20 07:39:49 -07:00
[ self setStories : nil ] ;
2012-06-22 18:01:08 -07:00
[ self setFeedUserProfiles : nil ] ;
2013-03-01 15:48:18 -08:00
self . inFeedDetail = YES ;
2012-06-27 21:28:04 -07:00
popoverHasFeedView = YES ;
2012-06-19 15:47:51 -07:00
2013-03-03 14:03:56 -08:00
UIBarButtonItem * newBackButton = [ [ UIBarButtonItem alloc ]
initWithTitle : @ "All"
style : UIBarButtonItemStyleBordered
target : nil
action : nil ] ;
[ feedsViewController . navigationItem setBackBarButtonItem : newBackButton ] ;
2012-07-10 12:34:58 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-24 11:44:16 -07:00
[ self . masterContainerViewController transitionToFeedDetail ] ;
2012-07-24 15:29:01 -07:00
} else {
2013-03-03 14:03:56 -08:00
[ navigationController pushViewController : feedDetailViewController
animated : YES ] ;
2012-07-20 22:00:30 -07:00
}
2013-03-01 15:48:18 -08:00
[ feedDetailViewController resetFeedDetail ] ;
[ feedDetailViewController fetchFeedDetail : 1 withCallback : nil ] ;
2013-06-16 14:09:28 -07:00
[ self flushQueuedReadStories : NO withCallback : nil ] ;
2012-06-19 15:47:51 -07:00
}
2012-11-09 14:13:44 -08:00
- ( void ) loadTryFeedDetailView : ( NSString * ) feedId
withStory : ( NSString * ) contentId
isSocial : ( BOOL ) social
withUser : ( NSDictionary * ) user
showFindingStory : ( BOOL ) showHUD {
2012-07-29 20:55:11 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPhone ) {
[ self . navigationController popToRootViewControllerAnimated : NO ] ;
2013-06-17 11:50:13 -07:00
[ self . navigationController dismissViewControllerAnimated : YES completion : nil ] ;
2013-02-21 17:57:32 -08:00
if ( self . feedsViewController . popoverController ) {
[ self . feedsViewController . popoverController dismissPopoverAnimated : NO ] ;
}
2012-07-29 20:55:11 -07:00
}
2012-07-28 23:31:12 -07:00
NSDictionary * feed = nil ;
2012-07-16 22:35:28 -07:00
if ( social ) {
feed = [ self . dictSocialFeeds objectForKey : feedId ] ;
2012-07-29 20:55:11 -07:00
self . isSocialView = YES ;
2012-08-01 12:41:02 -07:00
self . inFindingStoryMode = YES ;
2012-07-29 20:55:11 -07:00
2012-07-28 23:31:12 -07:00
if ( feed = = nil ) {
feed = user ;
2012-08-06 19:21:39 -07:00
self . isTryFeedView = YES ;
2012-07-28 23:31:12 -07:00
}
2012-07-16 22:35:28 -07:00
} else {
feed = [ self . dictFeeds objectForKey : feedId ] ;
2012-07-28 23:31:12 -07:00
if ( feed = = nil ) {
2012-07-29 20:55:11 -07:00
feed = user ;
2012-08-06 19:21:39 -07:00
self . isTryFeedView = YES ;
2012-07-29 20:55:11 -07:00
2012-07-28 23:31:12 -07:00
}
2012-07-16 22:35:28 -07:00
[ self setIsSocialView : NO ] ;
[ self setInFindingStoryMode : NO ] ;
}
2012-07-29 20:55:11 -07:00
2012-11-13 12:28:16 -08:00
self . tryFeedStoryId = contentId ;
self . activeFeed = feed ;
self . activeFolder = nil ;
2012-07-16 19:45:14 -07:00
[ self loadFeedDetailView ] ;
2012-11-09 14:13:44 -08:00
if ( showHUD ) {
2013-03-01 15:48:18 -08:00
[ self . storyPageControl showShareHUD : @ "Finding story..." ] ;
2012-11-09 14:13:44 -08:00
}
2012-07-16 19:45:14 -07:00
}
2012-06-26 12:12:31 -07:00
- ( BOOL ) isSocialFeed : ( NSString * ) feedIdStr {
if ( [ feedIdStr length ] > 6 ) {
NSString * feedIdSubStr = [ feedIdStr substringToIndex : 6 ] ;
if ( [ feedIdSubStr isEqualToString : @ "social" ] ) {
return YES ;
}
}
return NO ;
}
2012-06-26 12:29:37 -07:00
2012-07-02 13:10:00 -07:00
- ( BOOL ) isPortrait {
UIInterfaceOrientation orientation = [ UIApplication sharedApplication ] . statusBarOrientation ;
if ( orientation = = UIInterfaceOrientationPortrait || orientation = = UIInterfaceOrientationPortraitUpsideDown ) {
return YES ;
} else {
return NO ;
}
}
2012-10-30 17:05:39 -07:00
- ( NSString * ) orderKey {
if ( self . isRiverView ) {
return [ NSString stringWithFormat : @ "folder:%@:order" , self . activeFolder ] ;
} else {
return [ NSString stringWithFormat : @ "%@:order" , [ self . activeFeed objectForKey : @ "id" ] ] ;
}
}
- ( NSString * ) readFilterKey {
if ( self . isRiverView ) {
return [ NSString stringWithFormat : @ "folder:%@:read_filter" , self . activeFolder ] ;
} else {
return [ NSString stringWithFormat : @ "%@:read_filter" , [ self . activeFeed objectForKey : @ "id" ] ] ;
}
}
2012-07-02 11:28:55 -07:00
- ( void ) confirmLogout {
UIAlertView * logoutConfirm = [ [ UIAlertView alloc ] initWithTitle : @ "Positive?"
message : nil
delegate : self
cancelButtonTitle : @ "Cancel"
otherButtonTitles : @ "Logout" , nil ] ;
[ logoutConfirm show ] ;
[ logoutConfirm setTag : 1 ] ;
}
2013-03-04 20:21:29 -08:00
- ( void ) showConnectToService : ( NSString * ) serviceName {
2013-03-05 08:49:37 -08:00
AuthorizeServicesViewController * serviceVC = [ [ AuthorizeServicesViewController alloc ] init ] ;
serviceVC . url = [ NSString stringWithFormat : @ "/oauth/%@_connect" , serviceName ] ;
serviceVC . type = serviceName ;
serviceVC . fromStory = YES ;
2013-03-04 20:21:29 -08:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2013-03-05 08:49:37 -08:00
UINavigationController * connectNav = [ [ UINavigationController alloc ]
initWithRootViewController : serviceVC ] ;
self . modalNavigationController = connectNav ;
self . modalNavigationController . modalPresentationStyle = UIModalPresentationFormSheet ;
2013-06-17 11:50:13 -07:00
[ self . masterContainerViewController presentViewController : modalNavigationController
animated : YES completion : nil ] ;
2013-03-04 20:21:29 -08:00
} else {
2013-03-05 08:49:37 -08:00
[ self . shareNavigationController pushViewController : serviceVC animated : YES ] ;
2013-03-04 20:21:29 -08:00
}
}
- ( void ) refreshUserProfile : ( void ( ^ ) ( ) ) callback {
2013-06-18 21:23:20 -04:00
NSURL * url = [ NSURL URLWithString : [ NSString stringWithFormat : @ "%@/social/load_user_profile" ,
2013-03-04 20:21:29 -08:00
NEWSBLUR_URL ] ] ;
ASIHTTPRequest * _request = [ ASIHTTPRequest requestWithURL : url ] ;
__weak ASIHTTPRequest * request = _request ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setFailedBlock : ^ ( void ) {
NSLog ( @ "Failed user profile" ) ;
callback ( ) ;
} ] ;
[ request setCompletionBlock : ^ ( void ) {
NSString * responseString = [ request responseString ] ;
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
self . dictUserProfile = [ results objectForKey : @ "user_profile" ] ;
self . dictSocialServices = [ results objectForKey : @ "services" ] ;
callback ( ) ;
} ] ;
[ request setTimeOutSeconds : 30 ] ;
[ request startAsynchronous ] ;
}
2012-07-02 11:28:55 -07:00
- ( void ) alertView : ( UIAlertView * ) alertView clickedButtonAtIndex : ( NSInteger ) buttonIndex {
if ( alertView . tag = = 1 ) { // this is logout
if ( buttonIndex = = 0 ) {
return ;
} else {
NSLog ( @ "Logging out..." ) ;
2013-06-18 21:23:20 -04:00
NSString * urlS = [ NSString stringWithFormat : @ "%@/reader/logout?api=1" ,
2012-07-02 11:28:55 -07:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlS ] ;
__block ASIHTTPRequest * request = [ ASIHTTPRequest requestWithURL : url ] ;
[ request setDelegate : self ] ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setFailedBlock : ^ ( void ) {
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
} ] ;
[ request setCompletionBlock : ^ ( void ) {
NSLog ( @ "Logout successful" ) ;
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
[ self showLogin ] ;
} ] ;
[ request setTimeOutSeconds : 30 ] ;
[ request startAsynchronous ] ;
[ ASIHTTPRequest setSessionCookies : nil ] ;
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
MBProgressHUD * HUD = [ MBProgressHUD showHUDAddedTo : self . view animated : YES ] ;
HUD . labelText = @ "Logging out..." ;
}
}
}
2012-06-20 07:39:49 -07:00
- ( void ) loadRiverFeedDetailView {
[ self setStories : nil ] ;
2012-06-22 18:01:08 -07:00
[ self setFeedUserProfiles : nil ] ;
2012-06-29 23:25:56 -07:00
self . inFeedDetail = YES ;
2012-06-27 14:37:37 -07:00
2012-06-20 07:39:49 -07:00
[ feedDetailViewController resetFeedDetail ] ;
[ feedDetailViewController fetchRiverPage : 1 withCallback : nil ] ;
2012-07-10 12:34:58 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-24 16:03:16 -07:00
[ self . masterContainerViewController transitionToFeedDetail ] ;
} else {
UIBarButtonItem * newBackButton = [ [ UIBarButtonItem alloc ] initWithTitle : @ "All"
style : UIBarButtonItemStyleBordered
target : nil
action : nil ] ;
[ feedsViewController . navigationItem setBackBarButtonItem : newBackButton ] ;
UINavigationController * navController = self . navigationController ;
[ navController pushViewController : feedDetailViewController animated : YES ] ;
}
2012-06-20 07:39:49 -07:00
}
2012-06-29 21:15:43 -07:00
- ( void ) adjustStoryDetailWebView {
2012-07-12 13:34:41 -07:00
// change UIWebView
2012-11-07 17:54:16 -08:00
[ storyPageControl . currentPage changeWebViewWidth ] ;
[ storyPageControl . nextPage changeWebViewWidth ] ;
2012-11-14 17:31:52 -08:00
[ storyPageControl . previousPage changeWebViewWidth ] ;
2012-07-23 15:27:20 -07:00
}
- ( void ) calibrateStoryTitles {
[ self . feedDetailViewController checkScroll ] ;
[ self . feedDetailViewController changeActiveFeedDetailRow ] ;
}
2012-07-12 13:34:41 -07:00
2012-12-12 15:08:24 -08:00
- ( void ) recalculateIntelligenceScores : ( id ) feedId {
2012-12-13 12:12:00 -08:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
NSMutableArray * newFeedStories = [ NSMutableArray array ] ;
2012-12-12 15:08:24 -08:00
2012-12-13 12:12:00 -08:00
for ( NSDictionary * story in self . activeFeedStories ) {
NSString * storyFeedId = [ NSString stringWithFormat : @ "%@" ,
[ story objectForKey : @ "story_feed_id" ] ] ;
if ( ! [ storyFeedId isEqualToString : feedIdStr ] ) {
[ newFeedStories addObject : story ] ;
continue ;
}
NSMutableDictionary * newStory = [ story mutableCopy ] ;
// If the story is visible , mark it as sticky so it doesn ; t go away on page loads .
int score = [ NewsBlurAppDelegate computeStoryScore : [ story objectForKey : @ "intelligence" ] ] ;
if ( score >= self . selectedIntelligence ) {
[ newStory setObject : [ NSNumber numberWithBool : YES ] forKey : @ "sticky" ] ;
}
NSNumber * zero = [ NSNumber numberWithInt : 0 ] ;
NSMutableDictionary * intelligence = [ NSMutableDictionary
dictionaryWithObjects : [ NSArray arrayWithObjects :
[ zero copy ] , [ zero copy ] ,
[ zero copy ] , [ zero copy ] , nil ]
forKeys : [ NSArray arrayWithObjects :
@ "author" , @ "feed" , @ "tags" , @ "title" , nil ] ] ;
NSDictionary * classifiers = [ self . activeClassifiers objectForKey : feedIdStr ] ;
for ( NSString * title in [ classifiers objectForKey : @ "titles" ] ) {
if ( [ [ intelligence objectForKey : @ "title" ] intValue ] <= 0 &&
[ [ story objectForKey : @ "story_title" ] containsString : title ] ) {
int score = [ [ [ classifiers objectForKey : @ "titles" ] objectForKey : title ] intValue ] ;
[ intelligence setObject : [ NSNumber numberWithInt : score ] forKey : @ "title" ] ;
}
}
for ( NSString * author in [ classifiers objectForKey : @ "authors" ] ) {
if ( [ [ intelligence objectForKey : @ "author" ] intValue ] <= 0 &&
2012-12-28 11:34:06 -08:00
[ [ story objectForKey : @ "story_authors" ] class ] ! = [ NSNull class ] &&
2012-12-13 12:12:00 -08:00
[ [ story objectForKey : @ "story_authors" ] containsString : author ] ) {
int score = [ [ [ classifiers objectForKey : @ "authors" ] objectForKey : author ] intValue ] ;
[ intelligence setObject : [ NSNumber numberWithInt : score ] forKey : @ "author" ] ;
}
}
for ( NSString * tag in [ classifiers objectForKey : @ "tags" ] ) {
if ( [ [ intelligence objectForKey : @ "tags" ] intValue ] <= 0 &&
2012-12-28 11:34:06 -08:00
[ [ story objectForKey : @ "story_tags" ] class ] ! = [ NSNull class ] &&
2012-12-13 12:12:00 -08:00
[ [ story objectForKey : @ "story_tags" ] containsObject : tag ] ) {
int score = [ [ [ classifiers objectForKey : @ "tags" ] objectForKey : tag ] intValue ] ;
[ intelligence setObject : [ NSNumber numberWithInt : score ] forKey : @ "tags" ] ;
}
}
for ( NSString * feed in [ classifiers objectForKey : @ "feeds" ] ) {
if ( [ [ intelligence objectForKey : @ "feed" ] intValue ] <= 0 &&
2012-12-27 18:37:05 -08:00
[ storyFeedId isEqualToString : feed ] ) {
2012-12-13 12:12:00 -08:00
int score = [ [ [ classifiers objectForKey : @ "feeds" ] objectForKey : feed ] intValue ] ;
[ intelligence setObject : [ NSNumber numberWithInt : score ] forKey : @ "feed" ] ;
}
}
[ newStory setObject : intelligence forKey : @ "intelligence" ] ;
[ newFeedStories addObject : newStory ] ;
}
self . activeFeedStories = newFeedStories ;
2012-12-12 15:08:24 -08:00
}
2012-06-20 08:33:16 -07:00
- ( void ) dragFeedDetailView : ( float ) y {
2012-06-24 20:08:39 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2012-07-10 12:34:58 -07:00
if ( UIInterfaceOrientationIsPortrait ( storyDetailViewController . interfaceOrientation ) ) {
2012-06-22 19:15:48 -07:00
y = y + 20 ;
if ( y > 955 ) {
self . feedDetailPortraitYCoordinate = 960 ;
} else if ( y < 950 && y > 200 ) {
2012-06-20 08:33:16 -07:00
self . feedDetailPortraitYCoordinate = y ;
2012-06-22 19:15:48 -07:00
}
2012-06-24 20:08:39 -07:00
[ userPreferences setInteger : self . feedDetailPortraitYCoordinate forKey : @ "feedDetailPortraitYCoordinate" ] ;
[ userPreferences synchronize ] ;
2012-06-29 21:15:43 -07:00
[ self adjustStoryDetailWebView ] ;
2012-06-20 08:33:16 -07:00
}
2011-10-25 09:47:55 -07:00
}
2012-06-20 19:18:29 -07:00
- ( void ) changeActiveFeedDetailRow {
[ feedDetailViewController changeActiveFeedDetailRow ] ;
2012-06-18 16:45:36 -07:00
}
2010-06-25 18:36:01 -04:00
- ( void ) loadStoryDetailView {
2011-10-27 09:44:58 -07:00
NSString * feedTitle ;
if ( self . isRiverView ) {
2012-10-03 15:46:02 -07:00
if ( [ self . activeFolder isEqualToString : @ "river_blurblogs" ] ) {
feedTitle = @ "All Shared Stories" ;
2012-12-07 15:17:22 -08:00
} else if ( [ self . activeFolder isEqualToString : @ "river_global" ] ) {
feedTitle = @ "Global Shared Stories" ;
2012-10-03 15:46:02 -07:00
} else if ( [ self . activeFolder isEqualToString : @ "everything" ] ) {
feedTitle = @ "All Stories" ;
2012-10-17 15:07:53 -07:00
} else if ( [ self . activeFolder isEqualToString : @ "saved_stories" ] ) {
feedTitle = @ "Saved Stories" ;
2012-10-03 15:46:02 -07:00
} else {
feedTitle = self . activeFolder ;
}
2011-10-27 09:44:58 -07:00
} else {
feedTitle = [ activeFeed objectForKey : @ "feed_title" ] ;
}
2012-07-20 19:55:38 -07:00
2012-12-18 17:29:23 -08:00
int activeStoryLocation = [ self locationOfActiveStory ] ;
if ( activeStoryLocation >= 0 ) {
BOOL animated = ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad &&
! self . tryFeedCategory ) ;
[ self . storyPageControl changePage : activeStoryLocation animated : animated ] ;
// [ self . storyPageControl updatePageWithActiveStory : activeStoryLocation ] ;
}
2012-07-24 16:03:16 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPhone ) {
2012-06-09 12:54:32 -07:00
UIBarButtonItem * newBackButton = [ [ UIBarButtonItem alloc ] initWithTitle : feedTitle style : UIBarButtonItemStyleBordered target : nil action : nil ] ;
[ feedDetailViewController . navigationItem setBackBarButtonItem : newBackButton ] ;
2012-11-05 15:12:42 -08:00
UINavigationController * navController = self . navigationController ;
[ navController pushViewController : storyPageControl animated : YES ] ;
2012-07-15 15:06:06 -07:00
[ navController . navigationItem setLeftBarButtonItem : [ [ UIBarButtonItem alloc ] initWithTitle : feedTitle style : UIBarButtonItemStyleBordered target : nil action : nil ] ] ;
2012-06-09 12:54:32 -07:00
navController . navigationItem . hidesBackButton = YES ;
}
2012-11-07 17:54:16 -08:00
2012-06-11 16:56:38 -07:00
}
2011-08-25 12:09:41 -07:00
- ( void ) navigationController : ( UINavigationController * ) navController
willShowViewController : ( UIViewController * ) viewController animated : ( BOOL ) animated {
2013-03-03 14:03:56 -08:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
[ viewController viewWillAppear : animated ] ;
2011-08-25 12:09:41 -07:00
}
2010-06-24 00:22:26 -04:00
}
2013-03-03 14:03:56 -08:00
- ( void ) navigationController : ( UINavigationController * ) navigationController didShowViewController : ( UIViewController * ) viewController animated : ( BOOL ) animated {
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
[ viewController viewDidAppear : animated ] ;
}
}
2010-11-11 23:48:27 -05:00
- ( void ) setTitle : ( NSString * ) title {
UILabel * label = [ [ UILabel alloc ] init ] ;
[ label setFont : [ UIFont boldSystemFontOfSize : 16.0 ] ] ;
[ label setBackgroundColor : [ UIColor clearColor ] ] ;
2013-02-14 15:36:21 -08:00
[ label setTextColor : UIColorFromRGB ( 0 x404040 ) ] ;
2010-11-11 23:48:27 -05:00
[ label setText : title ] ;
2012-11-13 14:49:53 -08:00
[ label setShadowOffset : CGSizeMake ( 0 , -1 ) ] ;
2013-02-14 15:36:21 -08:00
[ label setShadowColor : UIColorFromRGB ( 0 xFAFAFA ) ] ;
2010-11-11 23:48:27 -05:00
[ label sizeToFit ] ;
[ navigationController . navigationBar . topItem setTitleView : label ] ;
}
2010-06-24 00:22:26 -04:00
2012-06-14 10:19:36 -07:00
- ( void ) showOriginalStory : ( NSURL * ) url {
2010-11-13 18:32:43 -05:00
self . activeOriginalStoryURL = url ;
2012-06-29 10:46:26 -07:00
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2013-06-17 11:50:13 -07:00
[ self . masterContainerViewController presentViewController : originalStoryViewController animated : YES completion : nil ] ;
2012-06-29 10:46:26 -07:00
} else {
2013-06-17 11:50:13 -07:00
[ self . navigationController presentViewController : originalStoryViewController animated : YES completion : nil ] ;
2012-06-29 10:46:26 -07:00
}
2010-11-13 18:32:43 -05:00
}
- ( void ) closeOriginalStory {
2013-06-17 11:50:13 -07:00
if ( ! [ self . presentedViewController isBeingDismissed ] ) {
[ originalStoryViewController dismissViewControllerAnimated : YES completion : nil ] ;
2013-03-04 17:15:50 -08:00
}
2010-11-13 18:32:43 -05:00
}
2010-06-24 00:22:26 -04:00
2012-07-10 12:34:58 -07:00
- ( void ) hideStoryDetailView {
if ( UI_USER _INTERFACE _IDIOM ( ) = = UIUserInterfaceIdiomPad ) {
2012-07-24 16:03:16 -07:00
[ self . masterContainerViewController transitionFromFeedDetail ] ;
2012-07-11 18:08:07 -07:00
} else {
[ self . navigationController popViewControllerAnimated : YES ] ;
2012-07-10 12:34:58 -07:00
}
}
2013-06-29 17:28:41 -07:00
# pragma mark - Story Traversal
2012-06-28 15:03:28 -07:00
- ( int ) indexOfNextUnreadStory {
2012-11-06 13:45:15 -08:00
int location = [ self locationOfNextUnreadStory ] ;
return [ self indexFromLocation : location ] ;
}
- ( int ) locationOfNextUnreadStory {
2011-08-08 09:58:15 -07:00
int activeLocation = [ self locationOfActiveStory ] ;
2011-07-24 21:47:58 -07:00
int readStatus = -1 ;
2011-08-08 09:58:15 -07:00
for ( int i = activeLocation + 1 ; i < [ self . activeFeedStoryLocations count ] ; i + + ) {
2012-11-06 13:45:15 -08:00
int storyIndex = [ [ self . activeFeedStoryLocations objectAtIndex : i ] intValue ] ;
NSDictionary * story = [ activeFeedStories objectAtIndex : storyIndex ] ;
2011-07-24 21:47:58 -07:00
readStatus = [ [ story objectForKey : @ "read_status" ] intValue ] ;
if ( readStatus = = 0 ) {
2012-11-06 13:45:15 -08:00
return i ;
2011-07-24 21:47:58 -07:00
}
}
2011-08-08 17:17:32 -07:00
if ( activeLocation > 0 ) {
for ( int i = activeLocation -1 ; i >= 0 ; i - - ) {
2012-11-06 13:45:15 -08:00
int storyIndex = [ [ self . activeFeedStoryLocations objectAtIndex : i ] intValue ] ;
NSDictionary * story = [ activeFeedStories objectAtIndex : storyIndex ] ;
2011-08-08 17:17:32 -07:00
readStatus = [ [ story objectForKey : @ "read_status" ] intValue ] ;
if ( readStatus = = 0 ) {
2012-11-06 13:45:15 -08:00
return i ;
2011-08-08 17:17:32 -07:00
}
2011-06-15 11:21:55 -04:00
}
}
return -1 ;
}
2012-06-28 15:03:28 -07:00
- ( int ) indexOfNextStory {
2012-11-06 13:45:15 -08:00
int location = [ self locationOfNextStory ] ;
return [ self indexFromLocation : location ] ;
}
- ( int ) locationOfNextStory {
2012-06-28 15:03:28 -07:00
int activeLocation = [ self locationOfActiveStory ] ;
int nextStoryLocation = activeLocation + 1 ;
if ( nextStoryLocation < [ self . activeFeedStoryLocations count ] ) {
2012-11-06 13:45:15 -08:00
return nextStoryLocation ;
2012-06-28 15:03:28 -07:00
}
return -1 ;
}
2011-06-15 11:21:55 -04:00
- ( int ) indexOfActiveStory {
2011-07-24 16:52:24 -07:00
for ( int i = 0 ; i < self . storyCount ; i + + ) {
2011-06-15 11:21:55 -04:00
NSDictionary * story = [ activeFeedStories objectAtIndex : i ] ;
if ( [ activeStory objectForKey : @ "id" ] = = [ story objectForKey : @ "id" ] ) {
return i ;
2011-06-14 10:35:33 -04:00
}
}
2011-06-15 11:21:55 -04:00
return -1 ;
2011-06-14 10:35:33 -04:00
}
2012-11-06 13:45:15 -08:00
- ( int ) indexOfStoryId : ( id ) storyId {
for ( int i = 0 ; i < self . storyCount ; i + + ) {
NSDictionary * story = [ activeFeedStories objectAtIndex : i ] ;
if ( [ story objectForKey : @ "id" ] = = storyId ) {
return i ;
}
}
return -1 ;
}
- ( int ) locationOfStoryId : ( id ) storyId {
for ( int i = 0 ; i < [ activeFeedStoryLocations count ] ; i + + ) {
if ( [ activeFeedStoryLocationIds objectAtIndex : i ] = = storyId ) {
return i ;
}
}
return -1 ;
}
2011-08-08 09:58:15 -07:00
- ( int ) locationOfActiveStory {
for ( int i = 0 ; i < [ activeFeedStoryLocations count ] ; i + + ) {
2012-11-28 15:46:11 -08:00
if ( [ [ activeFeedStoryLocationIds objectAtIndex : i ]
isEqualToString : [ self . activeStory objectForKey : @ "id" ] ] ) {
2011-08-08 09:58:15 -07:00
return i ;
}
}
return -1 ;
}
2012-11-06 13:45:15 -08:00
- ( int ) indexFromLocation : ( int ) location {
if ( location = = -1 ) return -1 ;
return [ [ activeFeedStoryLocations objectAtIndex : location ] intValue ] ;
}
2011-08-22 18:25:33 -07:00
- ( void ) pushReadStory : ( id ) storyId {
if ( [ self . readStories lastObject ] ! = storyId ) {
[ self . readStories addObject : storyId ] ;
}
}
- ( id ) popReadStory {
if ( storyCount = = 0 ) {
return nil ;
} else {
[ self . readStories removeLastObject ] ;
id lastStory = [ self . readStories lastObject ] ;
return lastStory ;
}
}
2013-06-21 18:35:06 -07:00
- ( NSString * ) activeOrder {
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
NSString * orderPrefDefault = [ userPreferences stringForKey : @ "default_order" ] ;
NSString * orderPref = [ userPreferences stringForKey : [ self orderKey ] ] ;
if ( orderPref ) {
return orderPref ;
} else if ( orderPrefDefault ) {
return orderPrefDefault ;
} else {
return @ "newest" ;
}
}
- ( NSString * ) activeReadFilter {
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
NSString * readFilterFeedPrefDefault = [ userPreferences stringForKey : @ "default_feed_read_filter" ] ;
NSString * readFilterFolderPrefDefault = [ userPreferences stringForKey : @ "default_folder_read_filter" ] ;
NSString * readFilterPref = [ userPreferences stringForKey : [ self readFilterKey ] ] ;
if ( readFilterPref ) {
return readFilterPref ;
} else if ( self . isRiverView || self . isSocialRiverView ) {
if ( readFilterFolderPrefDefault ) {
return readFilterFolderPrefDefault ;
} else {
return @ "unread" ;
}
} else {
if ( readFilterFeedPrefDefault ) {
return readFilterFeedPrefDefault ;
} else {
return @ "all" ;
}
}
}
2013-06-29 17:28:41 -07:00
# pragma mark - Unread Counts
- ( void ) populateDictUnreadCounts {
self . dictUnreadCounts = [ NSMutableDictionary dictionary ] ;
[ self . database inDatabase : ^ ( FMDatabase * db ) {
FMResultSet * cursor = [ db executeQuery : @ "SELECT * FROM unread_counts" ] ;
while ( [ cursor next ] ) {
NSDictionary * unreadCounts = [ cursor resultDictionary ] ;
[ self . dictUnreadCounts setObject : unreadCounts forKey : [ unreadCounts objectForKey : @ "feed_id" ] ] ;
}
} ] ;
}
2013-06-21 18:35:06 -07:00
2011-07-26 08:37:10 -07:00
- ( int ) unreadCount {
2012-08-13 17:07:26 -07:00
if ( self . isRiverView || self . isSocialRiverView ) {
2011-10-31 10:10:38 -07:00
return [ self unreadCountForFolder : nil ] ;
} else {
return [ self unreadCountForFeed : nil ] ;
}
}
2012-07-29 22:14:08 -07:00
- ( int ) allUnreadCount {
int total = 0 ;
for ( id key in self . dictSocialFeeds ) {
NSDictionary * feed = [ self . dictSocialFeeds objectForKey : key ] ;
total + = [ [ feed objectForKey : @ "ps" ] intValue ] ;
total + = [ [ feed objectForKey : @ "nt" ] intValue ] ;
NSLog ( @ "feed title and number is %@ %i" , [ feed objectForKey : @ "feed_title" ] , ( [ [ feed objectForKey : @ "ps" ] intValue ] + [ [ feed objectForKey : @ "nt" ] intValue ] ) ) ;
NSLog ( @ "total is %i" , total ) ;
}
2013-06-29 17:28:41 -07:00
for ( id key in self . dictUnreadCounts ) {
NSDictionary * feed = [ self . dictUnreadCounts objectForKey : key ] ;
2012-07-29 22:14:08 -07:00
total + = [ [ feed objectForKey : @ "ps" ] intValue ] ;
total + = [ [ feed objectForKey : @ "nt" ] intValue ] ;
2013-06-29 17:28:41 -07:00
// NSLog ( @ "feed title and number is %@ %i" , [ feed objectForKey : @ "feed_title" ] , ( [ [ feed objectForKey : @ "ps" ] intValue ] + [ [ feed objectForKey : @ "nt" ] intValue ] ) ) ;
// NSLog ( @ "total is %i" , total ) ;
2012-07-29 22:14:08 -07:00
}
return total ;
}
2011-10-31 10:10:38 -07:00
- ( int ) unreadCountForFeed : ( NSString * ) feedId {
2011-08-09 17:58:43 -07:00
int total = 0 ;
2011-10-31 10:10:38 -07:00
NSDictionary * feed ;
if ( feedId ) {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2012-10-07 15:47:21 -04:00
if ( [ feedIdStr containsString : @ "social:" ] ) {
2012-08-01 12:41:02 -07:00
feed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
} else {
2013-06-29 17:28:41 -07:00
feed = [ self . dictUnreadCounts objectForKey : feedIdStr ] ;
2012-08-01 12:41:02 -07:00
}
2011-10-31 10:10:38 -07:00
} else {
feed = self . activeFeed ;
}
total + = [ [ feed objectForKey : @ "ps" ] intValue ] ;
2011-08-09 17:58:43 -07:00
if ( [ self selectedIntelligence ] <= 0 ) {
2011-10-31 10:10:38 -07:00
total + = [ [ feed objectForKey : @ "nt" ] intValue ] ;
2011-08-09 17:58:43 -07:00
}
if ( [ self selectedIntelligence ] <= -1 ) {
2011-10-31 10:10:38 -07:00
total + = [ [ feed objectForKey : @ "ng" ] intValue ] ;
2011-08-09 17:58:43 -07:00
}
2011-10-31 10:10:38 -07:00
2011-08-09 17:58:43 -07:00
return total ;
}
2011-10-31 10:10:38 -07:00
- ( int ) unreadCountForFolder : ( NSString * ) folderName {
int total = 0 ;
NSArray * folder ;
2013-02-06 15:15:43 -08:00
if ( [ folderName isEqual : @ "river_blurblogs" ] ||
( ! folderName && [ self . activeFolder isEqual : @ "river_blurblogs" ] ) ) {
2012-08-13 17:07:26 -07:00
for ( id feedId in self . dictSocialFeeds ) {
total + = [ self unreadCountForFeed : feedId ] ;
}
2013-02-06 15:15:43 -08:00
} else if ( [ folderName isEqual : @ "river_global" ] ||
( ! folderName && [ self . activeFolder isEqual : @ "river_global" ] ) ) {
2012-12-07 15:17:22 -08:00
total = 0 ;
2013-02-06 15:15:43 -08:00
} else if ( [ folderName isEqual : @ "everything" ] ||
( ! folderName && [ self . activeFolder isEqual : @ "everything" ] ) ) {
2013-06-29 17:28:41 -07:00
for ( id feedId in self . dictUnreadCounts ) {
2011-12-01 09:01:18 -08:00
total + = [ self unreadCountForFeed : feedId ] ;
}
2011-10-31 10:10:38 -07:00
} else {
2011-12-01 09:01:18 -08:00
if ( ! folderName ) {
folder = [ self . dictFolders objectForKey : self . activeFolder ] ;
} else {
folder = [ self . dictFolders objectForKey : folderName ] ;
}
2011-10-31 10:10:38 -07:00
2011-12-01 09:01:18 -08:00
for ( id feedId in folder ) {
total + = [ self unreadCountForFeed : feedId ] ;
}
2011-10-31 10:10:38 -07:00
}
return total ;
2011-07-26 08:37:10 -07:00
}
2012-10-07 15:47:21 -04:00
2012-10-12 15:33:40 -04:00
- ( UnreadCounts * ) splitUnreadCountForFeed : ( NSString * ) feedId {
UnreadCounts * counts = [ UnreadCounts alloc ] ;
2013-06-29 17:28:41 -07:00
NSDictionary * feedCounts ;
2012-10-07 15:47:21 -04:00
2013-06-29 17:28:41 -07:00
if ( ! feedId ) {
feedId = [ self . activeFeed objectForKey : @ "id" ] ;
2012-10-07 15:47:21 -04:00
}
2013-06-29 17:28:41 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
feedCounts = [ self . dictUnreadCounts objectForKey : feedIdStr ] ;
2012-10-07 15:47:21 -04:00
2013-06-29 17:28:41 -07:00
counts . ps + = [ [ feedCounts objectForKey : @ "ps" ] intValue ] ;
counts . nt + = [ [ feedCounts objectForKey : @ "nt" ] intValue ] ;
counts . ng + = [ [ feedCounts objectForKey : @ "ng" ] intValue ] ;
2012-10-07 15:47:21 -04:00
return counts ;
}
2012-10-12 15:33:40 -04:00
- ( UnreadCounts * ) splitUnreadCountForFolder : ( NSString * ) folderName {
UnreadCounts * counts = [ UnreadCounts alloc ] ;
2012-10-07 15:47:21 -04:00
NSArray * folder ;
2012-10-14 17:30:03 -07:00
if ( [ [ self . folderCountCache objectForKey : folderName ] boolValue ] ) {
counts . ps = [ [ self . folderCountCache objectForKey : [ NSString stringWithFormat : @ "%@-ps" , folderName ] ] intValue ] ;
counts . nt = [ [ self . folderCountCache objectForKey : [ NSString stringWithFormat : @ "%@-nt" , folderName ] ] intValue ] ;
counts . ng = [ [ self . folderCountCache objectForKey : [ NSString stringWithFormat : @ "%@-ng" , folderName ] ] intValue ] ;
return counts ;
}
2013-02-06 15:15:43 -08:00
if ( [ folderName isEqual : @ "river_blurblogs" ] ||
( ! folderName && [ self . activeFolder isEqual : @ "river_blurblogs" ] ) ) {
2012-10-07 15:47:21 -04:00
for ( id feedId in self . dictSocialFeeds ) {
[ counts addCounts : [ self splitUnreadCountForFeed : feedId ] ] ;
}
2013-02-06 15:15:43 -08:00
} else if ( [ folderName isEqual : @ "river_global" ] ||
( ! folderName && [ self . activeFolder isEqual : @ "river_global" ] ) ) {
2012-12-07 15:17:22 -08:00
// Nothing for global
2013-02-06 15:15:43 -08:00
} else if ( [ folderName isEqual : @ "everything" ] ||
( ! folderName && [ self . activeFolder isEqual : @ "everything" ] ) ) {
2013-02-21 12:19:15 -08:00
for ( NSArray * folder in [ self . dictFolders allValues ] ) {
for ( id feedId in folder ) {
[ counts addCounts : [ self splitUnreadCountForFeed : feedId ] ] ;
}
2012-10-07 15:47:21 -04:00
}
} else {
if ( ! folderName ) {
folder = [ self . dictFolders objectForKey : self . activeFolder ] ;
} else {
folder = [ self . dictFolders objectForKey : folderName ] ;
}
for ( id feedId in folder ) {
[ counts addCounts : [ self splitUnreadCountForFeed : feedId ] ] ;
}
}
2012-10-14 17:30:03 -07:00
if ( ! self . folderCountCache ) {
self . folderCountCache = [ [ NSMutableDictionary alloc ] init ] ;
}
[ self . folderCountCache setObject : [ NSNumber numberWithBool : YES ] forKey : folderName ] ;
[ self . folderCountCache setObject : [ NSNumber numberWithInt : counts . ps ] forKey : [ NSString stringWithFormat : @ "%@-ps" , folderName ] ] ;
[ self . folderCountCache setObject : [ NSNumber numberWithInt : counts . nt ] forKey : [ NSString stringWithFormat : @ "%@-nt" , folderName ] ] ;
[ self . folderCountCache setObject : [ NSNumber numberWithInt : counts . ng ] forKey : [ NSString stringWithFormat : @ "%@-ng" , folderName ] ] ;
2012-10-07 15:47:21 -04:00
return counts ;
}
2013-06-29 17:28:41 -07:00
# pragma mark - Story Management
2011-07-24 16:52:24 -07:00
- ( void ) addStories : ( NSArray * ) stories {
2011-07-20 22:21:11 -07:00
self . activeFeedStories = [ self . activeFeedStories arrayByAddingObjectsFromArray : stories ] ;
2011-07-24 16:52:24 -07:00
self . storyCount = [ self . activeFeedStories count ] ;
2011-07-29 21:27:37 -07:00
[ self calculateStoryLocations ] ;
2012-11-26 09:54:20 -08:00
self . storyLocationsCount = [ self . activeFeedStoryLocations count ] ;
2011-07-24 16:52:24 -07:00
}
- ( void ) setStories : ( NSArray * ) activeFeedStoriesValue {
self . activeFeedStories = activeFeedStoriesValue ;
self . storyCount = [ self . activeFeedStories count ] ;
2011-11-03 18:08:24 -07:00
self . recentlyReadStories = [ NSMutableArray array ] ;
self . recentlyReadFeeds = [ NSMutableSet set ] ;
2011-07-29 21:27:37 -07:00
[ self calculateStoryLocations ] ;
2012-11-26 09:54:20 -08:00
self . storyLocationsCount = [ self . activeFeedStoryLocations count ] ;
2011-07-20 22:21:11 -07:00
}
2012-06-22 18:01:08 -07:00
- ( void ) setFeedUserProfiles : ( NSArray * ) activeFeedUserProfilesValue {
self . activeFeedUserProfiles = activeFeedUserProfilesValue ;
}
- ( void ) addFeedUserProfiles : ( NSArray * ) activeFeedUserProfilesValue {
self . activeFeedUserProfiles = [ self . activeFeedUserProfiles arrayByAddingObjectsFromArray : activeFeedUserProfilesValue ] ;
}
2011-07-24 20:34:54 -07:00
- ( void ) markActiveStoryRead {
2011-08-08 09:58:15 -07:00
int activeLocation = [ self locationOfActiveStory ] ;
if ( activeLocation = = -1 ) {
return ;
}
2012-07-29 20:55:11 -07:00
// changes the story layout in story feed detail
[ self . feedDetailViewController changeActiveStoryTitleCellLayout ] ;
2012-08-07 11:27:00 -07:00
2011-08-22 18:25:33 -07:00
int activeIndex = [ [ activeFeedStoryLocations objectAtIndex : activeLocation ] intValue ] ;
2012-06-29 13:48:00 -07:00
2012-06-29 12:54:52 -07:00
NSDictionary * feed ;
2012-08-07 11:27:00 -07:00
NSDictionary * friendFeed ;
2012-07-29 13:24:03 -07:00
id feedId ;
2012-06-29 13:48:00 -07:00
NSString * feedIdStr ;
2012-08-08 12:02:54 -07:00
NSDictionary * story = [ activeFeedStories objectAtIndex : activeIndex ] ;
2012-08-10 18:10:07 -07:00
NSMutableArray * otherFriendShares = [ [ self . activeStory objectForKey : @ "shared_by_friends" ] mutableCopy ] ;
NSMutableArray * otherFriendComments = [ [ self . activeStory objectForKey : @ "commented_by_friends" ] mutableCopy ] ;
2012-06-29 12:54:52 -07:00
2012-08-10 18:10:07 -07:00
if ( self . isSocialView ) {
2012-06-29 13:48:00 -07:00
feedId = [ self . activeStory objectForKey : @ "social_user_id" ] ;
feedIdStr = [ NSString stringWithFormat : @ "social:%@" , feedId ] ;
feed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
2012-08-10 18:10:07 -07:00
[ otherFriendShares removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendShares ) ;
[ otherFriendComments removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendComments ) ;
// make sure we set the active feed
self . activeFeed = feed ;
} else if ( self . isSocialRiverView ) {
2012-12-07 15:17:22 -08:00
if ( [ [ self . activeStory objectForKey : @ "friend_user_ids" ] count ] ) {
feedId = [ [ self . activeStory objectForKey : @ "friend_user_ids" ] objectAtIndex : 0 ] ;
feedIdStr = [ NSString stringWithFormat : @ "social:%@" , feedId ] ;
feed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
2012-08-10 18:10:07 -07:00
2012-12-07 15:17:22 -08:00
[ otherFriendShares removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendShares ) ;
[ otherFriendComments removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendComments ) ;
2012-08-08 12:02:54 -07:00
2012-12-07 15:17:22 -08:00
// make sure we set the active feed
self . activeFeed = feed ;
}
2012-06-29 12:54:52 -07:00
} else {
2012-06-29 13:48:00 -07:00
feedId = [ self . activeStory objectForKey : @ "story_feed_id" ] ;
feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2012-06-29 12:54:52 -07:00
feed = [ self . dictFeeds objectForKey : feedIdStr ] ;
2012-08-08 12:02:54 -07:00
// make sure we set the active feed
self . activeFeed = feed ;
2011-11-15 09:25:50 -08:00
}
2012-06-29 13:48:00 -07:00
2012-08-07 11:27:00 -07:00
// decrement all other friend feeds if they have the same story
2012-08-08 12:02:54 -07:00
if ( self . isSocialView || self . isSocialRiverView ) {
2012-08-10 18:10:07 -07:00
for ( int i = 0 ; i < otherFriendShares . count ; i + + ) {
feedIdStr = [ NSString stringWithFormat : @ "social:%@" ,
[ otherFriendShares objectAtIndex : i ] ] ;
friendFeed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
[ self markStoryRead : story feed : friendFeed ] ;
}
for ( int i = 0 ; i < otherFriendComments . count ; i + + ) {
2012-06-29 13:48:00 -07:00
feedIdStr = [ NSString stringWithFormat : @ "social:%@" ,
2012-08-10 18:10:07 -07:00
[ otherFriendComments objectAtIndex : i ] ] ;
2012-08-07 11:27:00 -07:00
friendFeed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
[ self markStoryRead : story feed : friendFeed ] ;
2012-06-29 13:48:00 -07:00
}
}
2012-06-29 17:37:49 -07:00
2012-08-07 11:27:00 -07:00
[ self . recentlyReadStories addObject : [ NSNumber numberWithInt : activeLocation ] ] ;
[ self markStoryRead : story feed : feed ] ;
2012-10-16 17:24:01 -07:00
self . activeStory = [ self . activeFeedStories objectAtIndex : activeIndex ] ;
}
- ( void ) markActiveStoryUnread {
int activeLocation = [ self locationOfActiveStory ] ;
if ( activeLocation = = -1 ) {
return ;
}
// changes the story layout in story feed detail
[ self . feedDetailViewController changeActiveStoryTitleCellLayout ] ;
int activeIndex = [ [ activeFeedStoryLocations objectAtIndex : activeLocation ] intValue ] ;
NSDictionary * feed ;
NSDictionary * friendFeed ;
id feedId ;
NSString * feedIdStr ;
NSDictionary * story = [ activeFeedStories objectAtIndex : activeIndex ] ;
NSMutableArray * otherFriendShares = [ [ self . activeStory objectForKey : @ "shared_by_friends" ] mutableCopy ] ;
NSMutableArray * otherFriendComments = [ [ self . activeStory objectForKey : @ "commented_by_friends" ] mutableCopy ] ;
if ( self . isSocialView ) {
feedId = [ self . activeStory objectForKey : @ "social_user_id" ] ;
feedIdStr = [ NSString stringWithFormat : @ "social:%@" , feedId ] ;
feed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
[ otherFriendShares removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendShares ) ;
[ otherFriendComments removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendComments ) ;
// make sure we set the active feed
self . activeFeed = feed ;
} else if ( self . isSocialRiverView ) {
feedId = [ [ self . activeStory objectForKey : @ "friend_user_ids" ] objectAtIndex : 0 ] ;
feedIdStr = [ NSString stringWithFormat : @ "social:%@" , feedId ] ;
feed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
[ otherFriendShares removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendShares ) ;
[ otherFriendComments removeObject : feedId ] ;
NSLog ( @ "otherFriendFeeds is %@" , otherFriendComments ) ;
// make sure we set the active feed
self . activeFeed = feed ;
} else {
feedId = [ self . activeStory objectForKey : @ "story_feed_id" ] ;
feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
feed = [ self . dictFeeds objectForKey : feedIdStr ] ;
// make sure we set the active feed
self . activeFeed = feed ;
}
// decrement all other friend feeds if they have the same story
if ( self . isSocialView || self . isSocialRiverView ) {
for ( int i = 0 ; i < otherFriendShares . count ; i + + ) {
feedIdStr = [ NSString stringWithFormat : @ "social:%@" ,
[ otherFriendShares objectAtIndex : i ] ] ;
friendFeed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
[ self markStoryUnread : story feed : friendFeed ] ;
}
for ( int i = 0 ; i < otherFriendComments . count ; i + + ) {
feedIdStr = [ NSString stringWithFormat : @ "social:%@" ,
[ otherFriendComments objectAtIndex : i ] ] ;
friendFeed = [ self . dictSocialFeeds objectForKey : feedIdStr ] ;
[ self markStoryUnread : story feed : friendFeed ] ;
}
}
[ self . recentlyReadStories removeObject : [ NSNumber numberWithInt : activeLocation ] ] ;
[ self markStoryUnread : story feed : feed ] ;
self . activeStory = [ self . activeFeedStories objectAtIndex : activeIndex ] ;
2011-11-10 18:28:22 -08:00
}
- ( NSDictionary * ) markVisibleStoriesRead {
NSMutableDictionary * feedsStories = [ NSMutableDictionary dictionary ] ;
for ( NSDictionary * story in self . activeFeedStories ) {
if ( [ [ story objectForKey : @ "read_status" ] intValue ] ! = 0 ) {
continue ;
}
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ story objectForKey : @ "story_feed_id" ] ] ;
NSDictionary * feed = [ self . dictFeeds objectForKey : feedIdStr ] ;
if ( ! [ feedsStories objectForKey : feedIdStr ] ) {
[ feedsStories setObject : [ NSMutableArray array ] forKey : feedIdStr ] ;
}
NSMutableArray * stories = [ feedsStories objectForKey : feedIdStr ] ;
[ stories addObject : [ story objectForKey : @ "id" ] ] ;
[ self markStoryRead : story feed : feed ] ;
}
return feedsStories ;
}
- ( void ) markStoryRead : ( NSString * ) storyId feedId : ( id ) feedId {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
NSDictionary * feed = [ self . dictFeeds objectForKey : feedIdStr ] ;
NSDictionary * story = nil ;
for ( NSDictionary * s in self . activeFeedStories ) {
if ( [ [ s objectForKey : @ "story_guid" ] isEqualToString : storyId ] ) {
story = s ;
break ;
}
}
[ self markStoryRead : story feed : feed ] ;
}
- ( void ) markStoryRead : ( NSDictionary * ) story feed : ( NSDictionary * ) feed {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "id" ] ] ;
2012-07-27 16:48:30 -07:00
NSMutableDictionary * newStory = [ story mutableCopy ] ;
2012-08-01 21:40:19 -07:00
[ newStory setValue : [ NSNumber numberWithInt : 1 ] forKey : @ "read_status" ] ;
2012-08-06 15:46:05 -07:00
// make the story as read in self . activeFeedStories
NSString * newStoryIdStr = [ NSString stringWithFormat : @ "%@" , [ newStory valueForKey : @ "id" ] ] ;
NSMutableArray * newActiveFeedStories = [ self . activeFeedStories mutableCopy ] ;
for ( int i = 0 ; i < [ newActiveFeedStories count ] ; i + + ) {
NSMutableArray * thisStory = [ [ newActiveFeedStories objectAtIndex : i ] mutableCopy ] ;
NSString * thisStoryIdStr = [ NSString stringWithFormat : @ "%@" , [ thisStory valueForKey : @ "id" ] ] ;
if ( [ newStoryIdStr isEqualToString : thisStoryIdStr ] ) {
[ newActiveFeedStories replaceObjectAtIndex : i withObject : newStory ] ;
break ;
}
}
self . activeFeedStories = newActiveFeedStories ;
2012-10-16 17:24:01 -07:00
2011-11-09 09:51:42 -08:00
self . visibleUnreadCount - = 1 ;
2012-07-27 16:48:30 -07:00
if ( ! [ self . recentlyReadFeeds containsObject : [ newStory objectForKey : @ "story_feed_id" ] ] ) {
[ self . recentlyReadFeeds addObject : [ newStory objectForKey : @ "story_feed_id" ] ] ;
2011-11-03 18:08:24 -07:00
}
2012-07-27 18:42:42 -07:00
2013-06-29 17:28:41 -07:00
NSDictionary * unreadCounts = [ self . dictUnreadCounts objectForKey : feedIdStr ] ;
NSMutableDictionary * newUnreadCounts = [ unreadCounts mutableCopy ] ;
2011-07-24 22:14:50 -07:00
int score = [ NewsBlurAppDelegate computeStoryScore : [ story objectForKey : @ "intelligence" ] ] ;
if ( score > 0 ) {
2013-06-29 17:28:41 -07:00
int unreads = MAX ( 0 , [ [ newUnreadCounts objectForKey : @ "ps" ] intValue ] - 1 ) ;
[ newUnreadCounts setValue : [ NSNumber numberWithInt : unreads ] forKey : @ "ps" ] ;
2011-07-24 22:14:50 -07:00
} else if ( score = = 0 ) {
2013-06-29 17:28:41 -07:00
int unreads = MAX ( 0 , [ [ newUnreadCounts objectForKey : @ "nt" ] intValue ] - 1 ) ;
[ newUnreadCounts setValue : [ NSNumber numberWithInt : unreads ] forKey : @ "nt" ] ;
2011-07-24 22:14:50 -07:00
} else if ( score < 0 ) {
2013-06-29 17:28:41 -07:00
int unreads = MAX ( 0 , [ [ newUnreadCounts objectForKey : @ "ng" ] intValue ] - 1 ) ;
[ newUnreadCounts setValue : [ NSNumber numberWithInt : unreads ] forKey : @ "ng" ] ;
2012-08-01 12:41:02 -07:00
}
2013-06-29 17:28:41 -07:00
[ self . dictUnreadCounts setObject : newUnreadCounts forKey : feedIdStr ] ;
2012-08-01 12:41:02 -07:00
2013-06-29 17:28:41 -07:00
[ self . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
NSString * storyHash = [ newStory objectForKey : @ "story_hash" ] ;
[ db executeUpdate : @ "UPDATE stories SET story_json = ? WHERE story_hash = ?" ,
[ newStory JSONRepresentation ] ,
storyHash ] ;
[ db executeUpdate : @ "DELETE FROM unread_hashes WHERE story_hash = ?" ,
storyHash ] ;
[ db executeUpdate : @ "UPDATE unread_counts SET ps = ?, nt = ?, ng = ? WHERE feed_id = ?" ,
[ newUnreadCounts objectForKey : @ "ps" ] ,
[ newUnreadCounts objectForKey : @ "nt" ] ,
[ newUnreadCounts objectForKey : @ "ng" ] ,
feedIdStr ] ;
} ] ;
2011-07-24 20:34:54 -07:00
}
2012-10-16 17:24:01 -07:00
- ( void ) markStoryUnread : ( NSString * ) storyId feedId : ( id ) feedId {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
NSDictionary * feed = [ self . dictFeeds objectForKey : feedIdStr ] ;
NSDictionary * story = nil ;
for ( NSDictionary * s in self . activeFeedStories ) {
if ( [ [ s objectForKey : @ "story_guid" ] isEqualToString : storyId ] ) {
story = s ;
break ;
}
}
[ self markStoryUnread : story feed : feed ] ;
}
- ( void ) markStoryUnread : ( NSDictionary * ) story feed : ( NSDictionary * ) feed {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "id" ] ] ;
NSMutableDictionary * newStory = [ story mutableCopy ] ;
[ newStory setValue : [ NSNumber numberWithInt : 0 ] forKey : @ "read_status" ] ;
// make the story as read in self . activeFeedStories
NSString * newStoryIdStr = [ NSString stringWithFormat : @ "%@" , [ newStory valueForKey : @ "id" ] ] ;
NSMutableArray * newActiveFeedStories = [ self . activeFeedStories mutableCopy ] ;
for ( int i = 0 ; i < [ newActiveFeedStories count ] ; i + + ) {
NSMutableArray * thisStory = [ [ newActiveFeedStories objectAtIndex : i ] mutableCopy ] ;
NSString * thisStoryIdStr = [ NSString stringWithFormat : @ "%@" , [ thisStory valueForKey : @ "id" ] ] ;
if ( [ newStoryIdStr isEqualToString : thisStoryIdStr ] ) {
[ newActiveFeedStories replaceObjectAtIndex : i withObject : newStory ] ;
break ;
}
}
self . activeFeedStories = newActiveFeedStories ;
self . visibleUnreadCount + = 1 ;
// if ( [ self . recentlyReadFeeds containsObject : [ newStory objectForKey : @ "story_feed_id" ] ] ) {
[ self . recentlyReadFeeds removeObject : [ newStory objectForKey : @ "story_feed_id" ] ] ;
// }
2013-06-29 17:28:41 -07:00
NSDictionary * unreadCounts = [ self . dictUnreadCounts objectForKey : [ feed objectForKey : feedIdStr ] ] ;
NSMutableDictionary * newUnreadCounts = [ unreadCounts mutableCopy ] ;
2012-10-16 17:24:01 -07:00
int score = [ NewsBlurAppDelegate computeStoryScore : [ story objectForKey : @ "intelligence" ] ] ;
if ( score > 0 ) {
2013-06-29 17:28:41 -07:00
int unreads = MAX ( 0 , [ [ newUnreadCounts objectForKey : @ "ps" ] intValue ] + 1 ) ;
[ newUnreadCounts setValue : [ NSNumber numberWithInt : unreads ] forKey : @ "ps" ] ;
2012-10-16 17:24:01 -07:00
} else if ( score = = 0 ) {
2013-06-29 17:28:41 -07:00
int unreads = MAX ( 0 , [ [ newUnreadCounts objectForKey : @ "nt" ] intValue ] + 1 ) ;
[ newUnreadCounts setValue : [ NSNumber numberWithInt : unreads ] forKey : @ "nt" ] ;
2012-10-16 17:24:01 -07:00
} else if ( score < 0 ) {
2013-06-29 17:28:41 -07:00
int unreads = MAX ( 0 , [ [ newUnreadCounts objectForKey : @ "ng" ] intValue ] + 1 ) ;
[ newUnreadCounts setValue : [ NSNumber numberWithInt : unreads ] forKey : @ "ng" ] ;
2012-10-16 17:24:01 -07:00
}
2013-06-29 17:28:41 -07:00
[ self . dictUnreadCounts setObject : newUnreadCounts forKey : feedIdStr ] ;
2012-10-16 17:24:01 -07:00
2013-06-29 17:28:41 -07:00
[ self . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
[ db executeUpdate : @ "UPDATE unread_counts SET ps = ?, nt = ?, ng = ? WHERE feed_id = ?" ,
[ newUnreadCounts objectForKey : @ "ps" ] ,
[ newUnreadCounts objectForKey : @ "nt" ] ,
[ newUnreadCounts objectForKey : @ "ng" ] ,
feedIdStr ] ;
} ] ;
2012-10-16 17:24:01 -07:00
}
2012-10-17 15:07:53 -07:00
- ( void ) markActiveStorySaved : ( BOOL ) saved {
NSMutableDictionary * newStory = [ self . activeStory mutableCopy ] ;
[ newStory setValue : [ NSNumber numberWithBool : saved ] forKey : @ "starred" ] ;
self . activeStory = newStory ;
// make the story as read in self . activeFeedStories
NSString * newStoryIdStr = [ NSString stringWithFormat : @ "%@" , [ newStory valueForKey : @ "id" ] ] ;
NSMutableArray * newActiveFeedStories = [ self . activeFeedStories mutableCopy ] ;
for ( int i = 0 ; i < [ newActiveFeedStories count ] ; i + + ) {
NSMutableArray * thisStory = [ [ newActiveFeedStories objectAtIndex : i ] mutableCopy ] ;
NSString * thisStoryIdStr = [ NSString stringWithFormat : @ "%@" , [ thisStory valueForKey : @ "id" ] ] ;
if ( [ newStoryIdStr isEqualToString : thisStoryIdStr ] ) {
[ newActiveFeedStories replaceObjectAtIndex : i withObject : newStory ] ;
break ;
}
}
self . activeFeedStories = newActiveFeedStories ;
2012-10-17 15:13:20 -07:00
if ( saved ) {
self . savedStoriesCount + = 1 ;
} else {
self . savedStoriesCount - = 1 ;
}
2012-10-17 15:07:53 -07:00
}
2012-10-16 17:24:01 -07:00
- ( void ) markActiveFeedAllRead {
2011-10-18 17:44:05 -07:00
id feedId = [ self . activeFeed objectForKey : @ "id" ] ;
2011-11-10 18:28:22 -08:00
[ self markFeedAllRead : feedId ] ;
2011-07-24 22:23:38 -07:00
}
2011-12-01 09:01:18 -08:00
- ( void ) markActiveFolderAllRead {
2013-02-06 15:15:43 -08:00
if ( [ self . activeFolder isEqual : @ "everything" ] ) {
2011-12-01 09:01:18 -08:00
for ( NSString * folderName in self . dictFoldersArray ) {
for ( id feedId in [ self . dictFolders objectForKey : folderName ] ) {
[ self markFeedAllRead : feedId ] ;
}
}
} else {
for ( id feedId in [ self . dictFolders objectForKey : self . activeFolder ] ) {
[ self markFeedAllRead : feedId ] ;
}
2011-11-09 09:51:42 -08:00
}
}
2011-11-10 18:28:22 -08:00
- ( void ) markFeedAllRead : ( id ) feedId {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2013-06-29 17:28:41 -07:00
NSMutableDictionary * unreadCounts = [ NSMutableDictionary dictionary ] ;
2011-11-10 18:28:22 -08:00
2013-06-29 17:28:41 -07:00
[ unreadCounts setValue : [ NSNumber numberWithInt : 0 ] forKey : @ "ps" ] ;
[ unreadCounts setValue : [ NSNumber numberWithInt : 0 ] forKey : @ "nt" ] ;
[ unreadCounts setValue : [ NSNumber numberWithInt : 0 ] forKey : @ "ng" ] ;
[ self . dictUnreadCounts setObject : unreadCounts forKey : feedIdStr ] ;
[ self . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
[ db executeUpdate : @ "UPDATE unread_counts SET ps = 0, nt = 0, ng = 0 WHERE feed_id = ?" ,
feedIdStr ] ;
} ] ;
2011-11-10 18:28:22 -08:00
}
2011-07-29 21:27:37 -07:00
- ( void ) calculateStoryLocations {
2011-11-09 09:51:42 -08:00
self . visibleUnreadCount = 0 ;
2011-08-01 09:43:13 -07:00
self . activeFeedStoryLocations = [ NSMutableArray array ] ;
2011-08-08 09:58:15 -07:00
self . activeFeedStoryLocationIds = [ NSMutableArray array ] ;
2011-07-29 21:27:37 -07:00
for ( int i = 0 ; i < self . storyCount ; i + + ) {
NSDictionary * story = [ self . activeFeedStories objectAtIndex : i ] ;
int score = [ NewsBlurAppDelegate computeStoryScore : [ story objectForKey : @ "intelligence" ] ] ;
2012-12-13 12:12:00 -08:00
if ( score >= self . selectedIntelligence || [ [ story objectForKey : @ "sticky" ] boolValue ] ) {
2011-07-29 21:27:37 -07:00
NSNumber * location = [ NSNumber numberWithInt : i ] ;
[ self . activeFeedStoryLocations addObject : location ] ;
2011-08-08 09:58:15 -07:00
[ self . activeFeedStoryLocationIds addObject : [ story objectForKey : @ "id" ] ] ;
2011-11-09 09:51:42 -08:00
if ( [ [ story objectForKey : @ "read_status" ] intValue ] = = 0 ) {
self . visibleUnreadCount + = 1 ;
}
2011-07-29 21:27:37 -07:00
}
}
}
2010-11-22 10:44:52 -05:00
+ ( int ) computeStoryScore : ( NSDictionary * ) intelligence {
int score = 0 ;
2011-07-26 08:37:10 -07:00
int title = [ [ intelligence objectForKey : @ "title" ] intValue ] ;
int author = [ [ intelligence objectForKey : @ "author" ] intValue ] ;
int tags = [ [ intelligence objectForKey : @ "tags" ] intValue ] ;
int score_max = MAX ( title , MAX ( author , tags ) ) ;
int score_min = MIN ( title , MIN ( author , tags ) ) ;
2011-07-24 20:07:38 -07:00
if ( score_max > 0 ) score = score_max ;
else if ( score_min < 0 ) score = score_min ;
2010-11-22 10:44:52 -05:00
2011-07-24 20:07:38 -07:00
if ( score = = 0 ) score = [ [ intelligence objectForKey : @ "feed" ] integerValue ] ;
2011-07-29 09:06:17 -07:00
// NSLog ( @ "%d/%d -- %d: %@" , score_max , score_min , score , intelligence ) ;
2010-11-22 10:44:52 -05:00
return score ;
}
2013-06-29 17:28:41 -07:00
# pragma mark - Feed Management
2011-12-04 21:09:16 -08:00
- ( NSString * ) extractParentFolderName : ( NSString * ) folderName {
2012-10-15 14:57:20 -07:00
if ( [ folderName containsString : @ "Top Level" ] ||
2013-02-06 15:15:43 -08:00
[ folderName isEqual : @ "everything" ] ) {
2011-12-04 21:09:16 -08:00
folderName = @ "" ;
}
if ( [ folderName containsString : @ " - " ] ) {
int lastFolderLoc = [ folderName rangeOfString : @ " - " options : NSBackwardsSearch ] . location ;
folderName = [ folderName substringToIndex : lastFolderLoc ] ;
} else {
folderName = @ "— Top Level —" ;
}
return folderName ;
}
- ( NSString * ) extractFolderName : ( NSString * ) folderName {
2012-10-15 14:57:20 -07:00
if ( [ folderName containsString : @ "Top Level" ] ||
2013-02-06 15:15:43 -08:00
[ folderName isEqual : @ "everything" ] ) {
2011-12-04 21:09:16 -08:00
folderName = @ "" ;
}
if ( [ folderName containsString : @ " - " ] ) {
int folder_loc = [ folderName rangeOfString : @ " - " options : NSBackwardsSearch ] . location ;
folderName = [ folderName substringFromIndex : ( folder_loc + 3 ) ] ;
}
return folderName ;
}
2012-12-28 11:34:06 -08:00
- ( NSDictionary * ) getFeed : ( NSString * ) feedId {
NSDictionary * feed ;
if ( self . isSocialView || self . isSocialRiverView ) {
feed = [ self . dictActiveFeeds objectForKey : feedId ] ;
// this is to catch when a user is already subscribed
if ( ! feed ) {
feed = [ self . dictFeeds objectForKey : feedId ] ;
}
} else {
feed = [ self . dictFeeds objectForKey : feedId ] ;
}
return feed ;
}
2011-12-04 21:09:16 -08:00
# pragma mark -
# pragma mark Feed Templates
2013-02-21 12:19:15 -08:00
+ ( void ) fillGradient : ( CGRect ) r startColor : ( UIColor * ) startColor endColor : ( UIColor * ) endColor {
CGContextRef context = UIGraphicsGetCurrentContext ( ) ;
UIGraphicsPushContext ( context ) ;
CGGradientRef gradient ;
2013-02-14 15:36:21 -08:00
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB ( ) ;
CGFloat locations [ 2 ] = { 0.0 f , 1.0 f } ;
CGFloat startRed , startGreen , startBlue , startAlpha ;
CGFloat endRed , endGreen , endBlue , endAlpha ;
[ startColor getRed : & startRed green : & startGreen blue : & startBlue alpha : & startAlpha ] ;
[ endColor getRed : & endRed green : & endGreen blue : & endBlue alpha : & endAlpha ] ;
CGFloat components [ 8 ] = {
startRed , startGreen , startBlue , startAlpha ,
endRed , endGreen , endBlue , endAlpha
} ;
2013-02-21 12:19:15 -08:00
gradient = CGGradientCreateWithColorComponents ( colorSpace , components , locations , 2 ) ;
2013-02-14 15:36:21 -08:00
CGColorSpaceRelease ( colorSpace ) ;
2013-02-15 16:41:20 -08:00
2013-02-14 15:36:21 -08:00
CGPoint startPoint = CGPointMake ( CGRectGetMinX ( r ) , r . origin . y ) ;
CGPoint endPoint = CGPointMake ( startPoint . x , r . origin . y + r . size . height ) ;
CGContextDrawLinearGradient ( context , gradient , startPoint , endPoint , 0 ) ;
2013-02-21 12:19:15 -08:00
CGGradientRelease ( gradient ) ;
2013-02-14 15:36:21 -08:00
UIGraphicsPopContext ( ) ;
}
2011-10-27 19:05:38 -07:00
+ ( UIView * ) makeGradientView : ( CGRect ) rect startColor : ( NSString * ) start endColor : ( NSString * ) end {
2012-07-15 15:06:06 -07:00
UIView * gradientView = [ [ UIView alloc ] initWithFrame : rect ] ;
2011-10-27 19:05:38 -07:00
CAGradientLayer * gradient = [ CAGradientLayer layer ] ;
2011-10-30 18:53:10 -07:00
gradient . frame = CGRectMake ( 0 , 1 , rect . size . width , rect . size . height -1 ) ;
2012-06-10 13:21:07 -07:00
gradient . opacity = 0.7 ;
2011-10-27 19:05:38 -07:00
unsigned int color = 0 ;
unsigned int colorFade = 0 ;
if ( [ start class ] = = [ NSNull class ] ) {
start = @ "505050" ;
}
if ( [ end class ] = = [ NSNull class ] ) {
end = @ "303030" ;
}
NSScanner * scanner = [ NSScanner scannerWithString : start ] ;
[ scanner scanHexInt : & color ] ;
NSScanner * scannerFade = [ NSScanner scannerWithString : end ] ;
[ scannerFade scanHexInt : & colorFade ] ;
gradient . colors = [ NSArray arrayWithObjects : ( id ) [ UIColorFromRGB ( color ) CGColor ] , ( id ) [ UIColorFromRGB ( colorFade ) CGColor ] , nil ] ;
2011-10-28 18:29:33 -07:00
CALayer * whiteBackground = [ CALayer layer ] ;
2011-10-30 18:53:10 -07:00
whiteBackground . frame = CGRectMake ( 0 , 1 , rect . size . width , rect . size . height -1 ) ;
2012-06-10 13:21:07 -07:00
whiteBackground . backgroundColor = [ [ UIColor whiteColor ] colorWithAlphaComponent : 0.7 ] . CGColor ;
2011-10-28 18:29:33 -07:00
[ gradientView . layer addSublayer : whiteBackground ] ;
2011-10-27 19:05:38 -07:00
[ gradientView . layer addSublayer : gradient ] ;
2011-10-28 18:29:33 -07:00
CALayer * topBorder = [ CALayer layer ] ;
2011-10-30 18:53:10 -07:00
topBorder . frame = CGRectMake ( 0 , 1 , rect . size . width , 1 ) ;
2012-06-10 13:21:07 -07:00
topBorder . backgroundColor = [ UIColorFromRGB ( colorFade ) colorWithAlphaComponent : 0.7 ] . CGColor ;
2011-10-30 15:06:25 -07:00
topBorder . opacity = 1 ;
2011-10-28 18:29:33 -07:00
[ gradientView . layer addSublayer : topBorder ] ;
CALayer * bottomBorder = [ CALayer layer ] ;
bottomBorder . frame = CGRectMake ( 0 , rect . size . height -1 , rect . size . width , 1 ) ;
2012-06-10 13:21:07 -07:00
bottomBorder . backgroundColor = [ UIColorFromRGB ( colorFade ) colorWithAlphaComponent : 0.7 ] . CGColor ;
2011-10-30 15:06:25 -07:00
bottomBorder . opacity = 1 ;
2011-10-28 18:29:33 -07:00
[ gradientView . layer addSublayer : bottomBorder ] ;
return gradientView ;
}
- ( UIView * ) makeFeedTitleGradient : ( NSDictionary * ) feed withRect : ( CGRect ) rect {
UIView * gradientView ;
2012-08-08 13:48:10 -07:00
if ( self . isRiverView || self . isSocialView || self . isSocialRiverView ) {
2011-10-28 18:29:33 -07:00
gradientView = [ NewsBlurAppDelegate
makeGradientView : rect
2012-06-30 21:28:48 -07:00
startColor : [ feed objectForKey : @ "favicon_fade" ]
endColor : [ feed objectForKey : @ "favicon_color" ] ] ;
2011-10-28 18:29:33 -07:00
2012-07-15 15:06:06 -07:00
UILabel * titleLabel = [ [ UILabel alloc ] init ] ;
2011-10-28 18:29:33 -07:00
titleLabel . text = [ feed objectForKey : @ "feed_title" ] ;
titleLabel . backgroundColor = [ UIColor clearColor ] ;
2013-06-17 11:50:13 -07:00
titleLabel . textAlignment = NSTextAlignmentLeft ;
titleLabel . lineBreakMode = NSLineBreakByTruncatingTail ;
2011-12-04 21:09:16 -08:00
titleLabel . numberOfLines = 1 ;
2011-10-28 18:29:33 -07:00
titleLabel . font = [ UIFont fontWithName : @ "Helvetica-Bold" size : 11.0 ] ;
titleLabel . shadowOffset = CGSizeMake ( 0 , 1 ) ;
if ( [ [ feed objectForKey : @ "favicon_text_color" ] class ] ! = [ NSNull class ] ) {
2011-11-30 18:46:11 -08:00
titleLabel . textColor = [ [ feed objectForKey : @ "favicon_text_color" ]
isEqualToString : @ "white" ] ?
2012-06-30 21:28:48 -07:00
[ UIColor whiteColor ] :
[ UIColor blackColor ] ;
2011-11-30 18:46:11 -08:00
titleLabel . shadowColor = [ [ feed objectForKey : @ "favicon_text_color" ]
isEqualToString : @ "white" ] ?
2012-06-30 21:28:48 -07:00
UIColorFromRGB ( 0 x202020 ) :
UIColorFromRGB ( 0 xd0d0d0 ) ;
2011-10-28 18:29:33 -07:00
} else {
titleLabel . textColor = [ UIColor whiteColor ] ;
titleLabel . shadowColor = [ UIColor blackColor ] ;
}
2011-12-04 21:09:16 -08:00
titleLabel . frame = CGRectMake ( 32 , 1 , rect . size . width -32 , 20 ) ;
2011-10-28 18:29:33 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "id" ] ] ;
UIImage * titleImage = [ Utilities getImage : feedIdStr ] ;
UIImageView * titleImageView = [ [ UIImageView alloc ] initWithImage : titleImage ] ;
2011-10-30 18:53:10 -07:00
titleImageView . frame = CGRectMake ( 8 , 3 , 16.0 , 16.0 ) ;
2011-10-28 18:29:33 -07:00
[ titleLabel addSubview : titleImageView ] ;
[ gradientView addSubview : titleLabel ] ;
[ gradientView addSubview : titleImageView ] ;
} else {
gradientView = [ NewsBlurAppDelegate
2012-11-06 17:26:08 -08:00
makeGradientView : CGRectMake ( 0 , -1 , rect . size . width , 10 )
2012-06-22 21:53:45 -07:00
// hard coding the 1024 as a hack for window . frame . size . width
2012-06-30 21:28:48 -07:00
startColor : [ feed objectForKey : @ "favicon_fade" ]
endColor : [ feed objectForKey : @ "favicon_color" ] ] ;
2011-10-28 18:29:33 -07:00
}
gradientView . opaque = YES ;
2011-10-27 19:05:38 -07:00
return gradientView ;
}
2011-08-18 09:56:52 -07:00
2011-12-02 16:23:00 -08:00
- ( UIView * ) makeFeedTitle : ( NSDictionary * ) feed {
2012-07-15 15:06:06 -07:00
UILabel * titleLabel = [ [ UILabel alloc ] init ] ;
2012-12-07 15:17:22 -08:00
if ( self . isSocialRiverView && [ self . activeFolder isEqualToString : @ "river_blurblogs" ] ) {
2012-10-03 15:46:02 -07:00
titleLabel . text = [ NSString stringWithFormat : @ " All Shared Stories" ] ;
2012-12-07 15:17:22 -08:00
} else if ( self . isSocialRiverView && [ self . activeFolder isEqualToString : @ "river_global" ] ) {
titleLabel . text = [ NSString stringWithFormat : @ " Global Shared Stories" ] ;
2012-10-03 15:46:02 -07:00
} else if ( self . isRiverView && [ self . activeFolder isEqualToString : @ "everything" ] ) {
titleLabel . text = [ NSString stringWithFormat : @ " All Stories" ] ;
2012-10-17 15:07:53 -07:00
} else if ( self . isRiverView && [ self . activeFolder isEqualToString : @ "saved_stories" ] ) {
titleLabel . text = [ NSString stringWithFormat : @ " Saved Stories" ] ;
2012-08-08 10:57:38 -07:00
} else if ( self . isRiverView ) {
2012-10-03 15:46:02 -07:00
titleLabel . text = [ NSString stringWithFormat : @ " %@" , self . activeFolder ] ;
2012-07-12 22:05:23 -07:00
} else if ( self . isSocialView ) {
titleLabel . text = [ NSString stringWithFormat : @ " %@" , [ feed objectForKey : @ "feed_title" ] ] ;
2011-12-02 16:23:00 -08:00
} else {
titleLabel . text = [ NSString stringWithFormat : @ " %@" , [ feed objectForKey : @ "feed_title" ] ] ;
}
titleLabel . backgroundColor = [ UIColor clearColor ] ;
2013-06-17 11:50:13 -07:00
titleLabel . textAlignment = NSTextAlignmentLeft ;
2011-12-02 16:23:00 -08:00
titleLabel . font = [ UIFont fontWithName : @ "Helvetica-Bold" size : 15.0 ] ;
2013-02-28 17:07:51 -08:00
titleLabel . textColor = UIColorFromRGB ( 0 x404040 ) ;
2013-06-17 11:50:13 -07:00
titleLabel . lineBreakMode = NSLineBreakByTruncatingTail ;
2011-12-04 21:09:16 -08:00
titleLabel . numberOfLines = 1 ;
2013-02-28 17:07:51 -08:00
titleLabel . shadowColor = UIColorFromRGB ( 0 xF5F5F5 ) ;
2011-12-02 16:23:00 -08:00
titleLabel . shadowOffset = CGSizeMake ( 0 , -1 ) ;
2012-07-12 22:05:23 -07:00
titleLabel . center = CGPointMake ( 0 , -2 ) ;
2011-12-02 16:23:00 -08:00
[ titleLabel sizeToFit ] ;
2012-07-12 22:05:23 -07:00
if ( ! self . isSocialView ) {
titleLabel . center = CGPointMake ( 28 , -2 ) ;
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "id" ] ] ;
UIImage * titleImage ;
2013-02-21 12:19:15 -08:00
if ( self . isSocialRiverView && [ self . activeFolder isEqualToString : @ "river_global" ] ) {
titleImage = [ UIImage imageNamed : @ "ak-icon-global.png" ] ;
} else if ( self . isSocialRiverView && [ self . activeFolder isEqualToString : @ "river_blurblogs" ] ) {
titleImage = [ UIImage imageNamed : @ "ak-icon-blurblogs.png" ] ;
2012-10-17 15:07:53 -07:00
} else if ( self . isRiverView && [ self . activeFolder isEqualToString : @ "everything" ] ) {
2013-02-21 12:19:15 -08:00
titleImage = [ UIImage imageNamed : @ "ak-icon-allstories.png" ] ;
2012-10-17 15:07:53 -07:00
} else if ( self . isRiverView && [ self . activeFolder isEqualToString : @ "saved_stories" ] ) {
2013-03-07 10:55:23 -05:00
titleImage = [ UIImage imageNamed : @ "clock.png" ] ;
2012-08-08 10:57:38 -07:00
} else if ( self . isRiverView ) {
2013-02-21 14:44:34 -08:00
titleImage = [ UIImage imageNamed : @ "g_icn_folder.png" ] ;
2012-07-12 22:05:23 -07:00
} else {
titleImage = [ Utilities getImage : feedIdStr ] ;
}
UIImageView * titleImageView = [ [ UIImageView alloc ] initWithImage : titleImage ] ;
titleImageView . frame = CGRectMake ( 0.0 , 2.0 , 16.0 , 16.0 ) ;
[ titleLabel addSubview : titleImageView ] ;
}
return titleLabel ;
}
- ( UIButton * ) makeRightFeedTitle : ( NSDictionary * ) feed {
2011-12-02 16:23:00 -08:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "id" ] ] ;
2012-07-25 17:29:29 -07:00
UIImage * titleImage = [ Utilities getImage : feedIdStr ] ;
2011-12-02 16:23:00 -08:00
2012-07-12 22:05:23 -07:00
titleImage = [ Utilities roundCorneredImage : titleImage radius : 6 ] ;
UIButton * titleImageButton = [ UIButton buttonWithType : UIButtonTypeCustom ] ;
titleImageButton . bounds = CGRectMake ( 0 , 0 , 32 , 32 ) ;
[ titleImageButton setImage : titleImage forState : UIControlStateNormal ] ;
return titleImageButton ;
2011-12-02 16:23:00 -08:00
}
2012-12-27 18:37:05 -08:00
# pragma mark -
# pragma mark Classifiers
- ( void ) toggleAuthorClassifier : ( NSString * ) author feedId : ( NSString * ) feedId {
int authorScore = [ [ [ [ self . activeClassifiers objectForKey : feedId ]
objectForKey : @ "authors" ]
objectForKey : author ] intValue ] ;
if ( authorScore > 0 ) {
authorScore = -1 ;
} else if ( authorScore < 0 ) {
authorScore = 0 ;
} else {
authorScore = 1 ;
}
NSMutableDictionary * feedClassifiers = [ [ self . activeClassifiers objectForKey : feedId ]
mutableCopy ] ;
NSMutableDictionary * authors = [ [ feedClassifiers objectForKey : @ "authors" ] mutableCopy ] ;
[ authors setObject : [ NSNumber numberWithInt : authorScore ] forKey : author ] ;
[ feedClassifiers setObject : authors forKey : @ "authors" ] ;
[ self . activeClassifiers setObject : feedClassifiers forKey : feedId ] ;
[ self . storyPageControl refreshHeaders ] ;
[ self . trainerViewController refresh ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/classifier/save" ,
2012-12-27 18:37:05 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
__block ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : author
forKey : authorScore >= 1 ? @ "like_author" :
authorScore <= -1 ? @ "dislike_author" :
@ "remove_like_author" ] ;
[ request setPostValue : feedId forKey : @ "feed_id" ] ;
[ request setCompletionBlock : ^ {
[ self . feedsViewController refreshFeedList : feedId ] ;
} ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
[ request setDelegate : self ] ;
[ request startAsynchronous ] ;
[ self recalculateIntelligenceScores : feedId ] ;
[ self . feedDetailViewController . storyTitlesTable reloadData ] ;
}
- ( void ) toggleTagClassifier : ( NSString * ) tag feedId : ( NSString * ) feedId {
NSLog ( @ "toggleTagClassifier: %@" , tag ) ;
int tagScore = [ [ [ [ self . activeClassifiers objectForKey : feedId ]
objectForKey : @ "tags" ]
objectForKey : tag ] intValue ] ;
if ( tagScore > 0 ) {
tagScore = -1 ;
} else if ( tagScore < 0 ) {
tagScore = 0 ;
} else {
tagScore = 1 ;
}
NSMutableDictionary * feedClassifiers = [ [ self . activeClassifiers objectForKey : feedId ]
mutableCopy ] ;
NSMutableDictionary * tags = [ [ feedClassifiers objectForKey : @ "tags" ] mutableCopy ] ;
[ tags setObject : [ NSNumber numberWithInt : tagScore ] forKey : tag ] ;
[ feedClassifiers setObject : tags forKey : @ "tags" ] ;
[ self . activeClassifiers setObject : feedClassifiers forKey : feedId ] ;
[ self . storyPageControl refreshHeaders ] ;
[ self . trainerViewController refresh ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/classifier/save" ,
2012-12-27 18:37:05 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
__block ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : tag
forKey : tagScore >= 1 ? @ "like_tag" :
tagScore <= -1 ? @ "dislike_tag" :
@ "remove_like_tag" ] ;
[ request setPostValue : feedId forKey : @ "feed_id" ] ;
[ request setCompletionBlock : ^ {
[ self . feedsViewController refreshFeedList : feedId ] ;
} ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
[ request setDelegate : self ] ;
[ request startAsynchronous ] ;
[ self recalculateIntelligenceScores : feedId ] ;
[ self . feedDetailViewController . storyTitlesTable reloadData ] ;
}
- ( void ) toggleTitleClassifier : ( NSString * ) title feedId : ( NSString * ) feedId score : ( int ) score {
NSLog ( @ "toggle Title: %@ (%@) / %d" , title , feedId , score ) ;
int titleScore = [ [ [ [ self . activeClassifiers objectForKey : feedId ]
objectForKey : @ "titles" ]
objectForKey : title ] intValue ] ;
if ( score ) {
titleScore = score ;
} else {
if ( titleScore > 0 ) {
titleScore = -1 ;
} else if ( titleScore < 0 ) {
titleScore = 0 ;
} else {
titleScore = 1 ;
}
}
NSMutableDictionary * feedClassifiers = [ [ self . activeClassifiers objectForKey : feedId ]
mutableCopy ] ;
NSMutableDictionary * titles = [ [ feedClassifiers objectForKey : @ "titles" ] mutableCopy ] ;
[ titles setObject : [ NSNumber numberWithInt : titleScore ] forKey : title ] ;
[ feedClassifiers setObject : titles forKey : @ "titles" ] ;
[ self . activeClassifiers setObject : feedClassifiers forKey : feedId ] ;
[ self . storyPageControl refreshHeaders ] ;
[ self . trainerViewController refresh ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/classifier/save" ,
2012-12-27 18:37:05 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
__block ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : title
forKey : titleScore >= 1 ? @ "like_title" :
titleScore <= -1 ? @ "dislike_title" :
@ "remove_like_title" ] ;
[ request setPostValue : feedId forKey : @ "feed_id" ] ;
[ request setCompletionBlock : ^ {
[ self . feedsViewController refreshFeedList : feedId ] ;
} ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
[ request setDelegate : self ] ;
[ request startAsynchronous ] ;
[ self recalculateIntelligenceScores : feedId ] ;
[ self . feedDetailViewController . storyTitlesTable reloadData ] ;
}
- ( void ) toggleFeedClassifier : ( NSString * ) feedId {
int feedScore = [ [ [ [ self . activeClassifiers objectForKey : feedId ]
objectForKey : @ "feeds" ]
objectForKey : feedId ] intValue ] ;
if ( feedScore > 0 ) {
feedScore = -1 ;
} else if ( feedScore < 0 ) {
feedScore = 0 ;
} else {
feedScore = 1 ;
}
NSMutableDictionary * feedClassifiers = [ [ self . activeClassifiers objectForKey : feedId ]
mutableCopy ] ;
NSMutableDictionary * feeds = [ [ feedClassifiers objectForKey : @ "feeds" ] mutableCopy ] ;
[ feeds setObject : [ NSNumber numberWithInt : feedScore ] forKey : feedId ] ;
[ feedClassifiers setObject : feeds forKey : @ "feeds" ] ;
[ self . activeClassifiers setObject : feedClassifiers forKey : feedId ] ;
[ self . storyPageControl refreshHeaders ] ;
[ self . trainerViewController refresh ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/classifier/save" ,
2012-12-27 18:37:05 -08:00
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
__block ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : feedId
forKey : feedScore >= 1 ? @ "like_feed" :
feedScore <= -1 ? @ "dislike_feed" :
@ "remove_like_feed" ] ;
[ request setPostValue : feedId forKey : @ "feed_id" ] ;
[ request setCompletionBlock : ^ {
[ self . feedsViewController refreshFeedList : feedId ] ;
} ] ;
[ request setDidFailSelector : @ selector ( requestFailed : ) ] ;
[ request setDelegate : self ] ;
[ request startAsynchronous ] ;
[ self recalculateIntelligenceScores : feedId ] ;
[ self . feedDetailViewController . storyTitlesTable reloadData ] ;
}
2013-03-06 14:29:40 -08:00
- ( void ) requestFailed : ( ASIHTTPRequest * ) request {
NSError * error = [ request error ] ;
NSLog ( @ "Error: %@" , error ) ;
[ self informError : error ] ;
}
2013-05-30 18:45:51 -07:00
# pragma mark -
# pragma mark Storing Stories for Offline
2013-06-14 19:21:30 -07:00
- ( int ) databaseSchemaVersion : ( FMDatabase * ) db {
2013-06-05 17:11:01 -07:00
int version = 0 ;
2013-06-14 19:21:30 -07:00
FMResultSet * resultSet = [ db executeQuery : @ "PRAGMA user_version" ] ;
2013-06-05 17:11:01 -07:00
if ( [ resultSet next ] ) {
version = [ resultSet intForColumnIndex : 0 ] ;
}
return version ;
}
2013-06-14 19:21:30 -07:00
- ( void ) createDatabaseConnection {
2013-06-26 16:22:44 -07:00
NSArray * paths = NSSearchPathForDirectoriesInDomains ( NSDocumentDirectory , NSUserDomainMask , YES ) ;
2013-06-05 17:11:01 -07:00
NSString * docsPath = [ paths objectAtIndex : 0 ] ;
2013-06-18 21:23:20 -04:00
NSString * dbName = [ NSString stringWithFormat : @ "%@.sqlite" , NEWSBLUR_HOST ] ;
2013-06-14 19:21:30 -07:00
NSString * path = [ docsPath stringByAppendingPathComponent : dbName ] ;
2013-06-05 17:11:01 -07:00
2013-06-14 19:21:30 -07:00
database = [ FMDatabaseQueue databaseQueueWithPath : path ] ;
[ database inDatabase : ^ ( FMDatabase * db ) {
[ self setupDatabase : db ] ;
} ] ;
}
- ( void ) setupDatabase : ( FMDatabase * ) db {
if ( [ self databaseSchemaVersion : db ] < CURRENT_DB _VERSION ) {
2013-06-05 17:11:01 -07:00
// FMDB cannot execute this query because FMDB tries to use prepared statements
2013-06-21 22:18:54 -07:00
[ db closeOpenResultSets ] ;
[ db executeUpdate : @ "drop table if exists `stories`" ] ;
[ db executeUpdate : @ "drop table if exists `unread_hashes`" ] ;
[ db executeUpdate : @ "drop table if exists `accounts`" ] ;
2013-06-29 17:28:41 -07:00
[ db executeUpdate : @ "drop table if exists `unread_counts`" ] ;
2013-06-22 19:34:12 -07:00
[ db executeUpdate : @ "drop table if exists `cached_images`" ] ;
2013-06-21 22:18:54 -07:00
// [ db executeUpdate : @ "drop table if exists `queued_read_hashes`" ] ;
2013-06-14 19:21:30 -07:00
NSLog ( @ "Dropped db: %@" , [ db lastErrorMessage ] ) ;
sqlite3_exec ( db . sqliteHandle , [ [ NSString stringWithFormat : @ "PRAGMA user_version = %d" , CURRENT_DB _VERSION ] UTF8String ] , NULL , NULL , NULL ) ;
}
2013-06-21 22:18:54 -07:00
NSString * createAccountsTable = [ NSString stringWithFormat : @ "create table if not exists accounts "
2013-06-20 19:25:57 -07:00
"("
" username varchar(36),"
" download_date date,"
" feeds_json text,"
" UNIQUE(username) ON CONFLICT REPLACE"
")" ] ;
2013-06-21 22:18:54 -07:00
[ db executeUpdate : createAccountsTable ] ;
2013-06-29 17:28:41 -07:00
NSString * createCountsTable = [ NSString stringWithFormat : @ "create table if not exists unread_counts "
2013-06-21 22:18:54 -07:00
"("
2013-06-29 17:28:41 -07:00
" feed_id varchar(20),"
2013-06-21 22:18:54 -07:00
" ps number,"
" nt number,"
" ng number,"
" UNIQUE(feed_id) ON CONFLICT REPLACE"
")" ] ;
2013-06-29 17:28:41 -07:00
[ db executeUpdate : createCountsTable ] ;
2013-06-20 19:25:57 -07:00
2013-06-14 19:21:30 -07:00
NSString * createStoryTable = [ NSString stringWithFormat : @ "create table if not exists stories "
"("
" story_feed_id number,"
" story_hash varchar(24),"
" story_timestamp number,"
" story_json text,"
" UNIQUE(story_hash) ON CONFLICT REPLACE"
")" ] ;
[ db executeUpdate : createStoryTable ] ;
2013-06-26 16:22:44 -07:00
NSString * indexStoriesFeed = @ "CREATE INDEX IF NOT EXISTS stories_story_feed_id ON stories (story_feed_id)" ;
[ db executeUpdate : indexStoriesFeed ] ;
2013-06-14 19:21:30 -07:00
NSString * createUnreadHashTable = [ NSString stringWithFormat : @ "create table if not exists unread_hashes "
"("
" story_feed_id number,"
" story_hash varchar(24),"
2013-06-16 21:39:38 -07:00
" story_timestamp number,"
2013-06-14 19:21:30 -07:00
" UNIQUE(story_hash) ON CONFLICT IGNORE"
")" ] ;
[ db executeUpdate : createUnreadHashTable ] ;
2013-06-26 16:22:44 -07:00
NSString * indexUnreadHashes = @ "CREATE INDEX IF NOT EXISTS unread_hashes_story_feed_id ON unread_hashes (story_feed_id)" ;
[ db executeUpdate : indexUnreadHashes ] ;
NSString * indexUnreadTimestamp = @ "CREATE INDEX IF NOT EXISTS unread_hashes_timestamp ON stories (story_timestamp)" ;
[ db executeUpdate : indexUnreadTimestamp ] ;
2013-06-14 19:21:30 -07:00
NSString * createReadTable = [ NSString stringWithFormat : @ "create table if not exists queued_read_hashes "
"("
" story_feed_id number,"
" story_hash varchar(24),"
" UNIQUE(story_hash) ON CONFLICT IGNORE"
")" ] ;
[ db executeUpdate : createReadTable ] ;
2013-06-26 16:22:44 -07:00
2013-06-22 19:34:12 -07:00
NSString * createImagesTable = [ NSString stringWithFormat : @ "create table if not exists cached_images "
"("
" story_feed_id number,"
" story_hash varchar(24),"
" image_url varchar(1024),"
2013-06-26 16:22:44 -07:00
" image_cached boolean"
2013-06-22 19:34:12 -07:00
")" ] ;
[ db executeUpdate : createImagesTable ] ;
2013-06-26 16:22:44 -07:00
NSString * indexImagesFeedId = @ "CREATE INDEX IF NOT EXISTS cached_images_story_feed_id ON cached_images (story_feed_id)" ;
[ db executeUpdate : indexImagesFeedId ] ;
NSString * indexImagesStoryHash = @ "CREATE INDEX IF NOT EXISTS cached_images_story_hash ON cached_images (story_hash)" ;
[ db executeUpdate : indexImagesStoryHash ] ;
2013-06-22 19:34:12 -07:00
2013-06-23 22:19:08 -07:00
NSError * error ;
NSArray * paths = NSSearchPathForDirectoriesInDomains ( NSCachesDirectory , NSUserDomainMask , YES ) ;
NSString * storyImagesDirectory = [ [ paths objectAtIndex : 0 ] stringByAppendingPathComponent : @ "story_images" ] ;
NSString * faviconsDirectory = [ [ paths objectAtIndex : 0 ] stringByAppendingPathComponent : @ "favicons" ] ;
NSString * avatarsDirectory = [ [ paths objectAtIndex : 0 ] stringByAppendingPathComponent : @ "avatars" ] ;
2013-06-05 17:11:01 -07:00
2013-06-23 22:19:08 -07:00
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : storyImagesDirectory ] ) {
[ [ NSFileManager defaultManager ] createDirectoryAtPath : storyImagesDirectory withIntermediateDirectories : NO attributes : nil error : & error ] ;
}
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : faviconsDirectory ] ) {
[ [ NSFileManager defaultManager ] createDirectoryAtPath : faviconsDirectory withIntermediateDirectories : NO attributes : nil error : & error ] ;
}
if ( ! [ [ NSFileManager defaultManager ] fileExistsAtPath : avatarsDirectory ] ) {
[ [ NSFileManager defaultManager ] createDirectoryAtPath : avatarsDirectory withIntermediateDirectories : NO attributes : nil error : & error ] ;
}
NSLog ( @ "Create db %d: %@" , [ db lastErrorCode ] , [ db lastErrorMessage ] ) ;
2013-05-30 18:45:51 -07:00
}
2013-06-21 22:18:54 -07:00
- ( void ) flushQueuedReadStories : ( BOOL ) forceCheck withCallback : ( void ( ^ ) ( ) ) callback {
if ( hasQueuedReadStories || forceCheck ) {
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
2013-06-23 22:19:08 -07:00
[ self flushOldCachedImages ] ;
2013-06-21 22:18:54 -07:00
[ self . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
NSMutableDictionary * hashes = [ NSMutableDictionary dictionary ] ;
FMResultSet * stories = [ db executeQuery : @ "SELECT * FROM queued_read_hashes" ] ;
while ( [ stories next ] ) {
NSString * storyFeedId = [ NSString stringWithFormat : @ "%@" , [ stories objectForColumnName : @ "story_feed_id" ] ] ;
NSString * storyHash = [ stories objectForColumnName : @ "story_hash" ] ;
if ( ! [ hashes objectForKey : storyFeedId ] ) {
[ hashes setObject : [ NSMutableArray array ] forKey : storyFeedId ] ;
}
[ [ hashes objectForKey : storyFeedId ] addObject : storyHash ] ;
}
if ( [ [ hashes allKeys ] count ] ) {
hasQueuedReadStories = NO ;
[ self syncQueuedReadStories : db withStories : hashes withCallback : callback ] ;
} else {
if ( callback ) callback ( ) ;
}
} ] ;
} ) ;
} else {
if ( callback ) callback ( ) ;
}
}
- ( void ) syncQueuedReadStories : ( FMDatabase * ) db withStories : ( NSDictionary * ) hashes withCallback : ( void ( ^ ) ( ) ) callback {
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_feed_stories_as_read" ,
NEWSBLUR_URL ] ;
NSURL * url = [ NSURL URLWithString : urlString ] ;
NSMutableArray * completedHashes = [ NSMutableArray array ] ;
for ( NSArray * storyHashes in [ hashes allValues ] ) {
[ completedHashes addObjectsFromArray : storyHashes ] ;
}
NSString * completedHashesStr = [ completedHashes componentsJoinedByString : @ "\" , \ "" ] ;
ASIFormDataRequest * request = [ ASIFormDataRequest requestWithURL : url ] ;
[ request setPostValue : [ hashes JSONRepresentation ] forKey : @ "feeds_stories" ] ;
[ request setDelegate : self ] ;
[ request setCompletionBlock : ^ {
NSLog ( @ "Completed clearing %@ hashes" , completedHashesStr ) ;
[ db executeUpdate : [ NSString stringWithFormat : @ "DELETE FROM queued_read_hashes WHERE story_hash in (\" % @ \ ")" , completedHashesStr ] ]
;
if ( callback ) callback ( ) ;
} ] ;
[ request setFailedBlock : ^ {
NSLog ( @ "Failed mark read queued." ) ;
hasQueuedReadStories = YES ;
if ( callback ) callback ( ) ;
} ] ;
[ request startAsynchronous ] ;
}
2013-06-14 19:21:30 -07:00
- ( void ) fetchUnreadHashes {
2013-06-18 21:23:20 -04:00
NSURL * url = [ NSURL URLWithString : [ NSString stringWithFormat : @ "%@/reader/unread_story_hashes?include_timestamps=true" ,
2013-06-14 19:21:30 -07:00
NEWSBLUR_URL ] ] ;
ASIHTTPRequest * _request = [ ASIHTTPRequest requestWithURL : url ] ;
__weak ASIHTTPRequest * request = _request ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setFailedBlock : ^ ( void ) {
NSLog ( @ "Failed fetch all story hashes." ) ;
} ] ;
[ request setCompletionBlock : ^ ( void ) {
[ self storeUnreadHashes : request ] ;
} ] ;
[ request setTimeOutSeconds : 30 ] ;
[ request startAsynchronous ] ;
2013-06-16 21:39:38 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self . feedsViewController showSyncingNotifier ] ;
} ) ;
2013-06-14 19:21:30 -07:00
}
- ( void ) storeUnreadHashes : ( ASIHTTPRequest * ) request {
NSString * responseString = [ request responseString ] ;
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
2013-06-20 19:25:57 -07:00
__block __typeof __ ( self ) _self = self ;
2013-06-14 19:21:30 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
2013-06-20 19:25:57 -07:00
[ _self . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
2013-06-14 19:21:30 -07:00
[ db executeUpdate : @ "DROP TABLE unread_hashes" ] ;
2013-06-20 19:25:57 -07:00
[ _self setupDatabase : db ] ;
2013-06-14 19:21:30 -07:00
NSDictionary * hashes = [ results objectForKey : @ "unread_feed_story_hashes" ] ;
for ( NSString * feed in [ hashes allKeys ] ) {
NSArray * story_hashes = [ hashes objectForKey : feed ] ;
2013-06-16 21:39:38 -07:00
for ( NSArray * story_hash _tuple in story_hashes ) {
2013-06-14 19:21:30 -07:00
[ db executeUpdate : @ "INSERT into unread_hashes"
2013-06-16 21:39:38 -07:00
"(story_feed_id, story_hash, story_timestamp) VALUES "
"(?, ?, ?)" ,
2013-06-14 19:21:30 -07:00
feed ,
2013-06-16 21:39:38 -07:00
[ story_hash _tuple objectAtIndex : 0 ] ,
[ story_hash _tuple objectAtIndex : 1 ]
2013-06-14 19:21:30 -07:00
] ;
}
}
} ] ;
2013-06-16 21:39:38 -07:00
2013-06-20 19:25:57 -07:00
_self . totalUnfetchedStoryCount = 0 ;
_self . remainingUnfetchedStoryCount = 0 ;
_self . latestFetchedStoryDate = 0 ;
2013-06-21 22:18:54 -07:00
_self . totalUncachedImagesCount = 0 ;
_self . remainingUncachedImagesCount = 0 ;
2013-06-20 19:25:57 -07:00
[ _self fetchAllUnreadStories ] ;
2013-06-14 19:21:30 -07:00
} ) ;
}
2013-06-16 14:09:28 -07:00
- ( NSArray * ) unfetchedStoryHashes {
NSMutableArray * hashes = [ NSMutableArray array ] ;
[ self . database inDatabase : ^ ( FMDatabase * db ) {
2013-06-16 21:39:38 -07:00
NSString * commonQuery = @ "FROM unread_hashes u "
"LEFT OUTER JOIN stories s ON (s.story_hash = u.story_hash) "
"WHERE s.story_hash IS NULL" ;
int count = [ db intForQuery : [ NSString stringWithFormat : @ "SELECT COUNT(1) %@" , commonQuery ] ] ;
2013-06-16 14:09:28 -07:00
if ( self . totalUnfetchedStoryCount = = 0 ) {
2013-06-16 21:39:38 -07:00
self . totalUnfetchedStoryCount = count ;
self . remainingUnfetchedStoryCount = self . totalUnfetchedStoryCount ;
} else {
self . remainingUnfetchedStoryCount = count ;
2013-06-16 14:09:28 -07:00
}
2013-06-16 21:39:38 -07:00
int limit = 100 ;
2013-06-21 22:18:54 -07:00
NSString * order ;
if ( [ [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "default_order" ] isEqualToString : @ "oldest" ] ) {
order = @ "ASC" ;
} else {
order = @ "DESC" ;
}
FMResultSet * cursor = [ db executeQuery : [ NSString stringWithFormat : @ "SELECT u.story_hash %@ ORDER BY u.story_timestamp %@ LIMIT %d" , commonQuery , order , limit ] ] ;
2013-06-16 21:39:38 -07:00
2013-06-16 14:09:28 -07:00
while ( [ cursor next ] ) {
[ hashes addObject : [ cursor objectForColumnName : @ "story_hash" ] ] ;
}
2013-06-16 21:39:38 -07:00
int start = ( int ) [ [ NSDate date ] timeIntervalSince1970 ] ;
int end = self . latestFetchedStoryDate ;
int seconds = start - ( end ? end : start ) ;
__block int hours = ( int ) round ( seconds / 60. f / 60. f ) ;
__block float progress = 0. f ;
if ( self . totalUnfetchedStoryCount ) {
progress = 1. f - ( ( float ) self . remainingUnfetchedStoryCount /
( float ) self . totalUnfetchedStoryCount ) ;
}
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self . feedsViewController showSyncingNotifier : progress hoursBack : hours ] ;
} ) ;
2013-06-16 14:09:28 -07:00
} ] ;
2013-06-14 19:21:30 -07:00
2013-06-16 14:09:28 -07:00
return hashes ;
2013-05-30 18:45:51 -07:00
}
2013-06-16 14:09:28 -07:00
- ( void ) fetchAllUnreadStories {
NSArray * hashes = [ self unfetchedStoryHashes ] ;
2013-06-16 21:39:38 -07:00
2013-06-16 14:09:28 -07:00
if ( [ hashes count ] = = 0 ) {
NSLog ( @ "Finished downloading unread stories. %d total" , self . totalUnfetchedStoryCount ) ;
2013-06-16 21:39:38 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2013-06-24 22:16:28 -07:00
[ self . feedsViewController showCachingNotifier : 0 hoursBack : 1 ] ;
2013-06-21 22:18:54 -07:00
[ self fetchAllUncachedImages ] ;
2013-06-16 21:39:38 -07:00
} ) ;
2013-06-16 14:09:28 -07:00
return ;
}
2013-06-18 21:23:20 -04:00
NSURL * url = [ NSURL URLWithString : [ NSString stringWithFormat : @ "%@/reader/river_stories?page=0&h=%@" ,
2013-06-16 14:09:28 -07:00
NEWSBLUR_URL , [ hashes componentsJoinedByString : @ "&h=" ] ] ] ;
2013-05-30 18:45:51 -07:00
ASIHTTPRequest * _request = [ ASIHTTPRequest requestWithURL : url ] ;
__weak ASIHTTPRequest * request = _request ;
[ request setResponseEncoding : NSUTF8StringEncoding ] ;
[ request setDefaultResponseEncoding : NSUTF8StringEncoding ] ;
[ request setFailedBlock : ^ ( void ) {
NSLog ( @ "Failed fetch all unreads." ) ;
} ] ;
[ request setCompletionBlock : ^ ( void ) {
[ self storeAllUnreadStories : request ] ;
} ] ;
[ request setTimeOutSeconds : 30 ] ;
[ request startAsynchronous ] ;
}
- ( void ) storeAllUnreadStories : ( ASIHTTPRequest * ) request {
NSString * responseString = [ request responseString ] ;
NSData * responseData = [ responseString dataUsingEncoding : NSUTF8StringEncoding ] ;
NSError * error ;
NSDictionary * results = [ NSJSONSerialization
JSONObjectWithData : responseData
options : kNilOptions
error : & error ] ;
2013-06-16 14:09:28 -07:00
__block BOOL anySuccess = NO ;
2013-06-20 19:25:57 -07:00
__block __typeof __ ( self ) _self = self ;
2013-05-30 18:45:51 -07:00
2013-06-20 19:25:57 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
[ _self . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
for ( NSDictionary * story in [ results objectForKey : @ "stories" ] ) {
2013-06-22 19:34:12 -07:00
BOOL inserted = [ 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-21 22:18:54 -07:00
[ story objectForKey : @ "story_feed_id" ] ,
[ story objectForKey : @ "story_hash" ] ,
[ story objectForKey : @ "story_timestamp" ] ,
[ story JSONRepresentation ]
] ;
2013-06-26 16:22:44 -07:00
if ( [ [ story objectForKey : @ "image_urls" ] class ] ! = [ NSNull class ] &&
[ [ story objectForKey : @ "image_urls" ] count ] ) {
for ( NSString * imageUrl in [ story objectForKey : @ "image_urls" ] ) {
[ db executeUpdate : @ "INSERT INTO cached_images "
"(story_feed_id, story_hash, image_url) VALUES "
"(?, ?, ?)" ,
[ story objectForKey : @ "story_feed_id" ] ,
[ story objectForKey : @ "story_hash" ] ,
imageUrl
] ;
}
2013-06-22 19:34:12 -07:00
}
2013-06-20 19:25:57 -07:00
if ( ! anySuccess && inserted ) anySuccess = YES ;
}
if ( anySuccess ) {
_self . latestFetchedStoryDate = [ [ [ [ results objectForKey : @ "stories" ] lastObject ]
objectForKey : @ "story_timestamp" ] intValue ] ;
}
} ] ;
2013-06-16 21:39:38 -07:00
if ( anySuccess ) {
2013-06-20 19:25:57 -07:00
[ _self fetchAllUnreadStories ] ;
} else {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ _self . feedsViewController hideNotifier ] ;
} ) ;
2013-06-16 14:09:28 -07:00
}
2013-06-20 19:25:57 -07:00
} ) ;
2013-05-30 18:45:51 -07:00
}
2013-06-21 22:18:54 -07:00
# pragma mark - - Offline - Image Cache
- ( NSArray * ) uncachedImageUrls {
NSMutableArray * urls = [ NSMutableArray array ] ;
[ self . database inDatabase : ^ ( FMDatabase * db ) {
2013-06-22 19:34:12 -07:00
NSString * commonQuery = @ "FROM cached_images c "
"INNER JOIN unread_hashes u ON (c.story_hash = u.story_hash) "
"WHERE c.image_cached is null " ;
2013-06-21 22:18:54 -07:00
int count = [ db intForQuery : [ NSString stringWithFormat : @ "SELECT COUNT(1) %@" , commonQuery ] ] ;
if ( self . totalUncachedImagesCount = = 0 ) {
self . totalUncachedImagesCount = count ;
self . remainingUncachedImagesCount = self . totalUncachedImagesCount ;
} else {
self . remainingUncachedImagesCount = count ;
}
2013-06-29 17:28:41 -07:00
int limit = 12 ;
2013-06-21 22:18:54 -07:00
NSString * order ;
if ( [ [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "default_order" ] isEqualToString : @ "oldest" ] ) {
order = @ "ASC" ;
} else {
order = @ "DESC" ;
}
2013-06-22 21:29:14 -07:00
NSString * sql = [ NSString stringWithFormat : @ "SELECT c.image_url, c.story_hash, u.story_timestamp %@ ORDER BY u.story_timestamp %@ LIMIT %d" , commonQuery , order , limit ] ;
2013-06-22 19:34:12 -07:00
FMResultSet * cursor = [ db executeQuery : sql ] ;
2013-06-21 22:18:54 -07:00
while ( [ cursor next ] ) {
2013-06-22 19:34:12 -07:00
[ urls addObject : @ [ [ cursor objectForColumnName : @ "image_url" ] ,
2013-06-22 21:29:14 -07:00
[ cursor objectForColumnName : @ "story_hash" ] ,
[ cursor objectForColumnName : @ "story_timestamp" ] ] ] ;
2013-06-21 22:18:54 -07:00
}
int start = ( int ) [ [ NSDate date ] timeIntervalSince1970 ] ;
2013-06-26 16:39:23 -07:00
int end = [ [ [ urls lastObject ] objectAtIndex : 2 ] intValue ] ;
2013-06-21 22:18:54 -07:00
int seconds = start - ( end ? end : start ) ;
__block int hours = ( int ) round ( seconds / 60. f / 60. f ) ;
__block float progress = 0. f ;
if ( self . totalUncachedImagesCount ) {
progress = 1. f - ( ( float ) self . remainingUncachedImagesCount /
( float ) self . totalUncachedImagesCount ) ;
}
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self . feedsViewController showCachingNotifier : progress hoursBack : hours ] ;
} ) ;
} ] ;
return urls ;
}
- ( void ) fetchAllUncachedImages {
NSArray * urls = [ self uncachedImageUrls ] ;
2013-06-22 19:34:12 -07:00
operationQueue = [ [ ASINetworkQueue alloc ] init ] ;
operationQueue . maxConcurrentOperationCount = 4 ;
operationQueue . delegate = self ;
2013-06-21 22:18:54 -07:00
if ( [ urls count ] = = 0 ) {
NSLog ( @ "Finished caching images. %d total" , self . totalUncachedImagesCount ) ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self . feedsViewController hideNotifier ] ;
} ) ;
return ;
}
2013-06-22 19:34:12 -07:00
for ( NSArray * urlArray in urls ) {
NSURL * url = [ NSURL URLWithString : [ urlArray objectAtIndex : 0 ] ] ;
NSString * storyHash = [ urlArray objectAtIndex : 1 ] ;
2013-06-21 22:18:54 -07:00
2013-06-22 19:34:12 -07:00
ASIHTTPRequest * request = [ ASIHTTPRequest requestWithURL : url ] ;
[ request setUserInfo : @ { @ "story_hash" : storyHash } ] ;
[ request setDelegate : self ] ;
[ request setDidFinishSelector : @ selector ( storeCachedImage : ) ] ;
[ request setDidFailSelector : @ selector ( storeCachedImage : ) ] ;
[ request setTimeOutSeconds : 5 ] ;
[ operationQueue addOperation : request ] ;
2013-06-16 08:15:40 -07:00
}
2013-06-22 21:29:14 -07:00
2013-06-22 19:34:12 -07:00
[ operationQueue setQueueDidFinishSelector : @ selector ( cachedImageQueueFinished : ) ] ;
[ operationQueue setShouldCancelAllRequestsOnFailure : NO ] ;
[ operationQueue go ] ;
// dispatch_async ( dispatch_get _main _queue ( ) , ^ {
// [ self . feedsViewController hideNotifier ] ;
// } ) ;
2013-06-16 08:15:40 -07:00
}
2013-06-21 22:18:54 -07:00
- ( void ) storeCachedImage : ( ASIHTTPRequest * ) request {
2013-06-22 19:34:12 -07:00
NSString * storyHash = [ [ request userInfo ] objectForKey : @ "story_hash" ] ;
2013-06-21 22:18:54 -07:00
2013-06-22 19:34:12 -07:00
if ( [ request responseStatusCode ] = = 200 ) {
NSData * responseData = [ request responseData ] ;
NSString * md5Url = [ Utilities md5 : [ [ request originalURL ] absoluteString ] ] ;
NSLog ( @ "Storing image: %@ (%d bytes - %d in queue)" , storyHash , [ responseData length ] , [ operationQueue requestsCount ] ) ;
NSFileManager * fileManager = [ NSFileManager defaultManager ] ;
NSArray * paths = NSSearchPathForDirectoriesInDomains ( NSCachesDirectory , NSUserDomainMask , YES ) ;
2013-06-23 22:19:08 -07:00
NSString * cacheDirectory = [ [ paths objectAtIndex : 0 ] stringByAppendingPathComponent : @ "story_images" ] ;
2013-06-22 19:34:12 -07:00
NSString * fullPath = [ cacheDirectory stringByAppendingPathComponent : [ NSString stringWithFormat : @ "%@" , md5Url ] ] ;
[ fileManager createFileAtPath : fullPath contents : responseData attributes : nil ] ;
2013-06-21 22:18:54 -07:00
} else {
2013-06-22 19:34:12 -07:00
NSLog ( @ "Failed to fetch: %@ / %@" , [ [ request originalURL ] absoluteString ] , storyHash ) ;
2013-06-16 08:15:40 -07:00
}
2013-06-22 19:34:12 -07:00
[ self . database inDatabase : ^ ( FMDatabase * db ) {
[ db executeUpdate : @ "UPDATE cached_images SET "
"image_cached = 1 WHERE story_hash = ?" ,
storyHash ] ;
} ] ;
}
- ( void ) cachedImageQueueFinished : ( ASINetworkQueue * ) queue {
NSLog ( @ "Queue finished: %d total (%d remaining)" , self . totalUncachedImagesCount , self . remainingUncachedImagesCount ) ;
[ self fetchAllUncachedImages ] ;
// dispatch_async ( dispatch_get _main _queue ( ) , ^ {
// [ self . feedsViewController hideNotifier ] ;
// } ) ;
2013-06-16 08:15:40 -07:00
}
2013-06-23 22:19:08 -07:00
- ( void ) flushOldCachedImages {
int deleted = 0 ;
NSFileManager * fileManager = [ NSFileManager defaultManager ] ;
NSArray * paths = NSSearchPathForDirectoriesInDomains ( NSCachesDirectory , NSUserDomainMask , YES ) ;
NSString * cacheDirectory = [ [ paths objectAtIndex : 0 ] stringByAppendingPathComponent : @ "story_images" ] ;
NSDirectoryEnumerator * en = [ fileManager enumeratorAtPath : cacheDirectory ] ;
NSString * file ;
while ( file = [ en nextObject ] )
{
NSError * error = nil ;
NSString * filepath = [ NSString stringWithFormat : [ cacheDirectory stringByAppendingString : @ "/%@" ] , file ] ;
NSDate * creationDate = [ [ fileManager attributesOfItemAtPath : filepath error : nil ] fileCreationDate ] ;
NSDate * d = [ [ NSDate date ] dateByAddingTimeInterval : -14 * 24 * 60 * 60 ] ;
NSDateFormatter * df = [ NSDateFormatter alloc ] ; // = [ NSDateFormatter initWithDateFormat : @ "yyyy-MM-dd" ] ;
[ df setDateFormat : @ "EEEE d" ] ;
if ( [ creationDate compare : d ] = = NSOrderedAscending ) {
[ [ NSFileManager defaultManager ]
removeItemAtPath : [ cacheDirectory stringByAppendingPathComponent : file ]
error : & error ] ;
deleted + = 1 ;
}
}
NSLog ( @ "Deleted %d old cached images" , deleted ) ;
}
- ( void ) prepareActiveCachedImages : ( FMDatabase * ) db {
activeCachedImages = [ NSMutableDictionary dictionary ] ;
2013-06-26 11:38:49 -07:00
NSDate * start = [ NSDate date ] ;
2013-06-23 22:19:08 -07:00
NSArray * feedIds ;
if ( isRiverView ) {
feedIds = activeFolderFeeds ;
} else if ( activeFeed ) {
feedIds = @ [ [ activeFeed objectForKey : @ "id" ] ] ;
}
NSString * sql = [ NSString stringWithFormat : @ "SELECT c.image_url, c.story_hash FROM cached_images c "
"WHERE c.image_cached = 1 AND c.story_feed_id in (%@)" ,
[ feedIds componentsJoinedByString : @ "," ] ] ;
FMResultSet * cursor = [ db executeQuery : sql ] ;
while ( [ cursor next ] ) {
2013-06-26 16:22:44 -07:00
NSString * storyHash = [ cursor objectForColumnName : @ "story_hash" ] ;
NSMutableArray * imageUrls ;
if ( ! [ activeCachedImages objectForKey : storyHash ] ) {
imageUrls = [ NSMutableArray array ] ;
[ activeCachedImages setObject : imageUrls forKey : storyHash ] ;
} else {
imageUrls = [ activeCachedImages objectForKey : storyHash ] ;
}
[ imageUrls addObject : [ cursor objectForColumnName : @ "image_url" ] ] ;
[ activeCachedImages setObject : imageUrls forKey : storyHash ] ;
2013-06-23 22:19:08 -07:00
}
2013-06-26 11:38:49 -07:00
2013-06-26 16:22:44 -07:00
NSLog ( @ "prepareActiveCachedImages time: %f" , ( [ [ NSDate date ] timeIntervalSinceDate : start ] ) ) ;
2013-06-23 22:19:08 -07:00
}
2012-10-07 15:47:21 -04:00
@ end
2013-05-30 18:45:51 -07:00
# pragma mark -
# pragma mark Unread Counts
2012-10-07 15:47:21 -04:00
2012-10-12 15:33:40 -04:00
@ implementation UnreadCounts
2012-10-07 15:47:21 -04:00
@ synthesize ps , nt , ng ;
- ( id ) init {
if ( self = [ super init ] ) {
ps = 0 ;
nt = 0 ;
ng = 0 ;
}
return self ;
}
2012-10-12 15:33:40 -04:00
- ( void ) addCounts : ( UnreadCounts * ) counts {
2012-10-07 15:47:21 -04:00
ps + = counts . ps ;
nt + = counts . nt ;
ng + = counts . ng ;
}
2012-07-12 22:05:23 -07:00
@ end