2011-08-25 12:09:41 -07:00
//
2020-08-27 21:26:12 -07:00
// FeedsObjCViewController . m
2010-06-20 11:04:23 -04:00
// NewsBlur
//
// Created by Samuel Clay on 6 / 16 / 10.
// Copyright NewsBlur 2010. All rights reserved .
//
2020-08-27 21:26:12 -07:00
# import "FeedsObjCViewController.h"
2010-06-21 17:17:26 -04:00
# import "NewsBlurAppDelegate.h"
2012-07-10 16:48:05 -07:00
# import "DashboardViewController.h"
2013-02-21 16:53:37 -08:00
# import "InteractionsModule.h"
# import "ActivityModule.h"
2011-07-18 09:56:48 -07:00
# import "FeedTableCell.h"
2014-12-02 18:36:38 -08:00
# import "DashboardViewController.h"
2012-07-12 00:10:42 -07:00
# import "UserProfileViewController.h"
2011-08-13 23:00:51 -07:00
# import "MBProgressHUD.h"
2015-09-16 16:53:07 -07:00
# import "SBJson4.h"
# import "NSObject+SBJSON.h"
2013-06-16 21:39:38 -07:00
# import "NBNotifier.h"
2011-10-17 09:28:40 -07:00
# import "Utilities.h"
2013-10-11 17:46:09 -07:00
# import "UIBarButtonItem+Image.h"
2013-03-03 17:37:54 -08:00
# import "AddSiteViewController.h"
2013-06-20 19:25:57 -07:00
# import "FMDatabase.h"
# import "FMDatabaseAdditions.h"
2013-06-21 17:48:06 -07:00
# import "IASKAppSettingsViewController.h"
# import "IASKSettingsReader.h"
2013-09-11 14:34:43 -07:00
# import "UIImageView+AFNetworking.h"
2013-09-24 17:18:20 -07:00
# import "NBBarButtonItem.h"
2018-08-29 14:55:37 -07:00
# import "UISearchBar+Field.h"
2014-02-12 20:09:37 -08:00
# import "StoriesCollection.h"
2018-10-04 16:59:07 -07:00
# import "PremiumManager.h"
2021-05-29 21:25:43 -07:00
# import "MenuViewController.h"
2020-01-27 20:27:44 -08:00
# import "NewsBlur-Swift.h"
2012-07-31 13:10:26 -07:00
2021-03-26 21:51:02 -07:00
static const CGFloat kPhoneTableViewRowHeight = 8.0 f ;
static const CGFloat kTableViewRowHeight = 8.0 f ;
static const CGFloat kBlurblogTableViewRowHeight = 9.0 f ;
static const CGFloat kPhoneBlurblogTableViewRowHeight = 9.0 f ;
static const CGFloat kFolderTitleHeight = 12.0 f ;
2013-10-18 18:37:11 -07:00
static UIFont * userLabelFont ;
2011-07-19 09:38:49 -07:00
2018-01-28 11:08:38 -05:00
static NSArray < NSString * > * NewsBlurTopSectionNames ;
2020-08-27 21:26:12 -07:00
@ interface FeedsObjCViewController ( )
2012-08-09 10:18:15 -07:00
@ property ( nonatomic , strong ) NSMutableDictionary * updatedDictSocialFeeds_ ;
@ property ( nonatomic , strong ) NSMutableDictionary * updatedDictFeeds_ ;
2012-08-16 20:10:50 -07:00
@ property ( readwrite ) BOOL inPullToRefresh_ ;
2022-02-16 16:09:21 -08:00
@ property ( nonatomic ) NSDate * leftAppDate ;
2019-05-31 20:32:08 -07:00
@ property ( nonatomic , strong ) NSMutableDictionary < NSIndexPath * , NSNumber * > * rowHeights ;
2021-05-21 20:57:06 -07:00
@ property ( nonatomic , strong ) NSMutableDictionary < NSNumber * , FolderTitleView * > * folderTitleViews ;
2022-09-24 21:36:40 -06:00
@ property ( nonatomic , strong ) NSIndexPath * lastRowAtIndexPath ;
@ property ( nonatomic ) NSInteger lastSection ;
2012-08-09 10:18:15 -07:00
@ end
2020-08-27 21:26:12 -07:00
@ implementation FeedsObjCViewController
2010-06-21 17:17:26 -04:00
@ synthesize appDelegate ;
2011-08-02 09:16:54 -07:00
@ synthesize feedTitlesTable ;
2010-06-20 11:04:23 -04:00
@ synthesize feedViewToolbar ;
2010-06-21 17:17:26 -04:00
@ synthesize feedScoreSlider ;
2012-06-19 10:55:46 -07:00
@ synthesize homeButton ;
2011-08-02 09:16:54 -07:00
@ synthesize intelligenceControl ;
2011-08-02 10:13:06 -07:00
@ synthesize activeFeedLocations ;
2011-10-31 10:10:38 -07:00
@ synthesize stillVisibleFeeds ;
2012-12-20 12:21:44 -08:00
@ synthesize visibleFolders ;
2011-08-04 17:27:31 -07:00
@ synthesize viewShowingAllFeeds ;
2011-10-14 09:51:27 -07:00
@ synthesize imageCache ;
2012-07-15 16:46:46 -07:00
@ synthesize currentRowAtIndexPath ;
2013-10-17 17:23:52 -07:00
@ synthesize currentSection ;
2012-08-15 19:31:34 -07:00
@ synthesize noFocusMessage ;
2017-11-15 10:55:16 -08:00
@ synthesize noFocusLabel ;
2012-08-15 19:31:34 -07:00
@ synthesize toolbarLeftMargin ;
2012-08-09 10:18:15 -07:00
@ synthesize updatedDictFeeds_ ;
@ synthesize updatedDictSocialFeeds_ ;
2012-08-16 20:10:50 -07:00
@ synthesize inPullToRefresh_ ;
2013-02-20 17:00:01 -08:00
@ synthesize addBarButton ;
@ synthesize settingsBarButton ;
2013-02-26 19:39:13 -08:00
@ synthesize activitiesButton ;
2013-10-17 17:23:52 -07:00
@ synthesize userAvatarButton ;
@ synthesize neutralCount ;
@ synthesize positiveCount ;
@ synthesize userLabel ;
@ synthesize greenIcon ;
2017-10-04 14:42:10 -07:00
@ synthesize yellowIcon ;
2013-06-16 21:39:38 -07:00
@ synthesize notifier ;
2013-06-20 20:38:40 -07:00
@ synthesize isOffline ;
2013-12-10 18:14:32 -08:00
@ synthesize interactiveFeedDetailTransition ;
2015-09-18 15:02:15 -07:00
@ synthesize avatarImageView ;
2010-06-20 11:04:23 -04:00
2010-06-21 17:17:26 -04:00
# pragma mark -
2011-08-24 21:44:16 -07:00
# pragma mark Globals
2010-06-21 17:17:26 -04:00
2010-06-20 11:04:23 -04:00
- ( id ) initWithNibName : ( NSString * ) nibNameOrNil bundle : ( NSBundle * ) nibBundleOrNil {
2010-06-21 17:17:26 -04:00
if ( self = [ super initWithNibName : nibNameOrNil bundle : nibBundleOrNil ] ) {
2010-06-20 11:04:23 -04:00
}
return self ;
}
2018-01-28 11:08:38 -05:00
+ ( void ) initialize {
2022-03-09 19:16:43 -07:00
// keep in sync with NewsBlurTopSection
2022-07-08 21:29:43 -07:00
NewsBlurTopSectionNames = @ [ / * 0 * / @ "infrequent" ,
/ * 1 * / @ "everything" ] ;
2018-01-28 11:08:38 -05:00
}
2010-06-20 11:04:23 -04:00
- ( void ) viewDidLoad {
2012-07-31 13:10:26 -07:00
[ super viewDidLoad ] ;
2019-05-31 20:32:08 -07:00
2020-08-29 21:19:32 -07:00
self . appDelegate = [ NewsBlurAppDelegate sharedAppDelegate ] ;
2019-05-31 20:32:08 -07:00
self . rowHeights = [ NSMutableDictionary dictionary ] ;
2021-05-21 20:57:06 -07:00
self . folderTitleViews = [ NSMutableDictionary dictionary ] ;
2019-05-31 20:32:08 -07:00
2016-09-13 15:38:51 -07:00
self . refreshControl = [ UIRefreshControl new ] ;
self . refreshControl . tintColor = UIColorFromLightDarkRGB ( 0 x0 , 0 xffffff ) ;
self . refreshControl . backgroundColor = UIColorFromRGB ( 0 xE3E6E0 ) ;
[ self . refreshControl addTarget : self action : @ selector ( refresh : ) forControlEvents : UIControlEventValueChanged ] ;
2018-11-12 19:28:44 -08:00
self . feedTitlesTable . refreshControl = self . refreshControl ;
2017-11-30 16:49:20 -08:00
self . feedViewToolbar . translatesAutoresizingMaskIntoConstraints = NO ;
2016-09-13 15:38:51 -07:00
2018-08-29 14:55:37 -07:00
self . searchBar = [ [ UISearchBar alloc ]
initWithFrame : CGRectMake ( 0 , 0 , CGRectGetWidth ( self . feedTitlesTable . frame ) , 44. ) ] ;
self . searchBar . delegate = self ;
[ self . searchBar setReturnKeyType : UIReturnKeySearch ] ;
self . searchBar . backgroundColor = UIColorFromRGB ( 0 xE3E6E0 ) ;
self . searchBar . tintColor = UIColorFromRGB ( 0 x0 ) ;
self . searchBar . nb_searchField . textColor = UIColorFromRGB ( 0 x0 ) ;
[ self . searchBar setSearchBarStyle : UISearchBarStyleMinimal ] ;
[ self . searchBar setAutocapitalizationType : UITextAutocapitalizationTypeNone ] ;
self . feedTitlesTable . tableHeaderView = self . searchBar ;
2021-03-26 21:51:02 -07:00
userLabelFont = [ UIFont fontWithName : @ "WhitneySSm-Medium" size : 15.0 ] ;
2011-08-24 21:44:16 -07:00
2013-06-21 18:35:06 -07:00
imageCache = [ [ NSCache alloc ] init ] ;
[ imageCache setDelegate : self ] ;
2011-08-26 09:34:30 -07:00
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( returnToApp )
name : UIApplicationWillEnterForegroundNotification
object : nil ] ;
2012-08-09 16:34:59 -07:00
2022-02-16 16:09:21 -08:00
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( leavingApp )
name : UIApplicationWillResignActiveNotification
object : nil ] ;
2013-06-21 18:35:06 -07:00
[ [ NSNotificationCenter defaultCenter ]
addObserver : self
selector : @ selector ( settingDidChange : )
name : kIASKAppSettingChanged
object : nil ] ;
2013-06-21 17:48:06 -07:00
2016-03-26 21:27:25 -07:00
[ self updateIntelligenceControlForOrientation : UIInterfaceOrientationUnknown ] ;
2012-08-15 19:31:34 -07:00
self . intelligenceControl . hidden = YES ;
2016-03-26 21:27:25 -07:00
[ self . intelligenceControl . subviews objectAtIndex : 3 ] . accessibilityLabel = @ "All" ;
[ self . intelligenceControl . subviews objectAtIndex : 2 ] . accessibilityLabel = @ "Unread" ;
[ self . intelligenceControl . subviews objectAtIndex : 1 ] . accessibilityLabel = @ "Focus" ;
[ self . intelligenceControl . subviews objectAtIndex : 0 ] . accessibilityLabel = @ "Saved" ;
2013-02-26 19:39:13 -08:00
2013-09-24 17:18:20 -07:00
[ [ UIBarButtonItem appearance ] setTintColor : UIColorFromRGB ( 0 x8F918B ) ] ;
[ [ UIBarButtonItem appearance ] setTitleTextAttributes : @ { NSForegroundColorAttributeName :
2016-03-02 13:42:30 -08:00
UIColorFromFixedRGB ( 0 x8F918B ) }
2013-09-24 17:18:20 -07:00
forState : UIControlStateNormal ] ;
[ [ UIBarButtonItem appearance ] setTitleTextAttributes : @ { NSForegroundColorAttributeName :
2016-03-02 13:42:30 -08:00
UIColorFromFixedRGB ( 0 x4C4D4A ) }
2013-09-24 17:18:20 -07:00
forState : UIControlStateHighlighted ] ;
2017-10-18 21:18:19 -07:00
self . view . backgroundColor = UIColorFromRGB ( 0 xf4f4f4 ) ;
2013-09-24 17:18:20 -07:00
self . navigationController . navigationBar . tintColor = UIColorFromRGB ( 0 x8F918B ) ;
self . navigationController . navigationBar . translucent = NO ;
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2013-02-27 19:25:57 -08:00
[ self layoutForInterfaceOrientation : orientation ] ;
2013-06-16 21:39:38 -07:00
2013-10-08 19:33:11 -07:00
UILongPressGestureRecognizer * longpress = [ [ UILongPressGestureRecognizer alloc ]
initWithTarget : self action : @ selector ( handleLongPress : ) ] ;
longpress . minimumPressDuration = 1.0 ;
longpress . delegate = self ;
[ self . feedTitlesTable addGestureRecognizer : longpress ] ;
2015-12-07 16:09:49 -08:00
[ [ ThemeManager themeManager ] addThemeGestureRecognizerToView : self . feedTitlesTable ] ;
2019-07-17 20:32:14 -07:00
[ self updateTheme ] ;
2013-09-24 17:18:20 -07:00
self . notifier = [ [ NBNotifier alloc ] initWithTitle : @ "Fetching stories..."
2017-10-12 21:53:53 -07:00
withOffset : CGPointMake ( 0 , 0 ) ] ;
2013-06-19 20:26:04 -07:00
[ self . view insertSubview : self . notifier belowSubview : self . feedViewToolbar ] ;
2020-08-29 21:19:32 -07:00
[ self . view addConstraint : [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeWidth relatedBy : NSLayoutRelationEqual toItem : self . innerView attribute : NSLayoutAttributeWidth multiplier : 1.0 constant : 0 ] ] ;
[ self . view addConstraint : [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeLeading relatedBy : NSLayoutRelationEqual toItem : self . innerView attribute : NSLayoutAttributeLeading multiplier : 1.0 constant : 0 ] ] ;
2017-10-30 11:30:12 -07:00
[ self . view addConstraint : [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeHeight relatedBy : NSLayoutRelationEqual toItem : nil attribute : NSLayoutAttributeNotAnAttribute multiplier : 1.0 constant : NOTIFIER_HEIGHT ] ] ;
2017-10-30 18:06:38 -07:00
self . notifier . topOffsetConstraint = [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeTop relatedBy : NSLayoutRelationEqual toItem : self . feedViewToolbar attribute : NSLayoutAttributeTop multiplier : 1.0 constant : 0 ] ;
2017-10-30 11:30:12 -07:00
[ self . view addConstraint : self . notifier . topOffsetConstraint ] ;
2013-10-17 17:23:52 -07:00
2017-11-15 10:47:57 -08:00
self . feedTitlesTable . backgroundColor = UIColorFromRGB ( 0 xf4f4f4 ) ;
2013-10-17 17:23:52 -07:00
self . feedTitlesTable . separatorColor = [ UIColor clearColor ] ;
2017-11-30 16:49:20 -08:00
self . feedTitlesTable . translatesAutoresizingMaskIntoConstraints = NO ;
2019-05-31 20:32:08 -07:00
self . feedTitlesTable . estimatedRowHeight = 0 ;
2013-10-17 17:23:52 -07:00
2021-12-08 20:50:10 -07:00
if ( @ available ( iOS 15.0 , * ) ) {
self . feedTitlesTable . sectionHeaderTopPadding = 0 ;
}
2021-05-21 20:57:06 -07:00
self . currentRowAtIndexPath = nil ;
self . currentSection = NewsBlurTopSectionAllStories ;
2022-09-24 21:36:40 -06:00
self . lastRowAtIndexPath = nil ;
self . lastSection = NewsBlurTopSectionAllStories ;
2021-05-21 20:57:06 -07:00
2020-10-30 20:58:27 -07:00
userAvatarButton . hidden = YES ;
2017-11-30 10:12:38 -08:00
self . noFocusMessage . hidden = YES ;
2021-04-24 21:55:36 -07:00
// [ self . navigationController . interactivePopGestureRecognizer addTarget : self action : @ selector ( handleGesture : ) ] ;
2013-12-11 18:06:22 -08:00
2022-09-24 21:36:40 -06:00
[ self addKeyCommandWithInput : UIKeyInputDownArrow modifierFlags : UIKeyModifierAlternate action : @ selector ( selectNextFeed : ) discoverabilityTitle : @ "Next Site" wantPriority : YES ] ;
[ self addKeyCommandWithInput : UIKeyInputUpArrow modifierFlags : UIKeyModifierAlternate action : @ selector ( selectPreviousFeed : ) discoverabilityTitle : @ "Previous Site" wantPriority : YES ] ;
[ self addKeyCommandWithInput : UIKeyInputDownArrow modifierFlags : UIKeyModifierShift action : @ selector ( selectNextFolder : ) discoverabilityTitle : @ "Next Folder" wantPriority : YES ] ;
[ self addKeyCommandWithInput : UIKeyInputUpArrow modifierFlags : UIKeyModifierShift action : @ selector ( selectPreviousFolder : ) discoverabilityTitle : @ "Previous Folder" wantPriority : YES ] ;
2018-08-29 14:55:37 -07:00
[ self addKeyCommandWithInput : @ "e" modifierFlags : UIKeyModifierCommand action : @ selector ( selectEverything : ) discoverabilityTitle : @ "Open All Stories" ] ;
2015-11-22 20:09:37 -05:00
[ self addKeyCommandWithInput : UIKeyInputLeftArrow modifierFlags : 0 action : @ selector ( selectPreviousIntelligence : ) discoverabilityTitle : @ "Switch Views" ] ;
[ self addKeyCommandWithInput : UIKeyInputRightArrow modifierFlags : 0 action : @ selector ( selectNextIntelligence : ) discoverabilityTitle : @ "Switch Views" ] ;
2018-08-29 14:55:37 -07:00
[ self addKeyCommandWithInput : @ "a" modifierFlags : UIKeyModifierCommand action : @ selector ( tapAddSite : ) discoverabilityTitle : @ "Add Site" ] ;
2010-06-20 11:04:23 -04:00
}
2010-06-25 18:36:01 -04:00
- ( void ) viewWillAppear : ( BOOL ) animated {
2014-09-26 18:35:40 -07:00
// NSTimeInterval start = [ NSDate timeIntervalSinceReferenceDate ] ;
2019-05-31 20:32:08 -07:00
[ self resetRowHeights ] ;
2021-04-24 21:55:36 -07:00
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad &&
// ! self . interactiveFeedDetailTransition ) {
//
// [ appDelegate . masterContainerViewController transitionFromFeedDetail ] ;
// }
2014-09-26 18:35:40 -07:00
// NSLog ( @ "Feed List timing 0: %f" , [ NSDate timeIntervalSinceReferenceDate ] - start ) ;
2012-07-15 16:46:46 -07:00
[ super viewWillAppear : animated ] ;
2012-07-16 19:45:14 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2016-03-26 21:27:25 -07:00
NSInteger intelligenceLevel = [ userPreferences integerForKey : @ "selectedIntelligence" ] ;
2012-07-16 19:45:14 -07:00
2016-03-26 21:27:25 -07:00
if ( intelligenceLevel = = 2 ) {
self . viewShowingAllFeeds = NO ;
[ self . intelligenceControl setSelectedSegmentIndex : 3 ] ;
[ appDelegate setSelectedIntelligence : 2 ] ;
} else if ( intelligenceLevel = = 1 ) {
2012-07-16 19:45:14 -07:00
self . viewShowingAllFeeds = NO ;
[ self . intelligenceControl setSelectedSegmentIndex : 2 ] ;
[ appDelegate setSelectedIntelligence : 1 ] ;
2016-03-26 21:27:25 -07:00
} else if ( intelligenceLevel = = 0 ) {
2012-07-16 19:45:14 -07:00
self . viewShowingAllFeeds = NO ;
[ self . intelligenceControl setSelectedSegmentIndex : 1 ] ;
[ appDelegate setSelectedIntelligence : 0 ] ;
2013-10-08 19:33:11 -07:00
} else {
// default state , ALL BLURBLOG STORIES
2012-07-16 19:45:14 -07:00
self . viewShowingAllFeeds = YES ;
[ self . intelligenceControl setSelectedSegmentIndex : 0 ] ;
[ appDelegate setSelectedIntelligence : 0 ] ;
}
2020-11-25 21:39:11 -08:00
// [ MBProgressHUD hideHUDForView : appDelegate . detailViewController . view animated : NO ] ;
2012-07-16 19:45:14 -07:00
2012-08-02 18:00:48 -07:00
// perform these only if coming from the feed detail view
if ( appDelegate . inFeedDetail ) {
appDelegate . inFeedDetail = NO ;
// reload the data and then set the highlight again
2019-05-31 20:32:08 -07:00
// [ self reloadFeedTitlesTable ] ;
2015-11-04 20:06:46 -08:00
// [ self refreshHeaderCounts ] ;
2012-08-02 18:00:48 -07:00
[ self redrawUnreadCounts ] ;
2013-10-17 17:23:52 -07:00
// [ self . feedTitlesTable selectRowAtIndexPath : self . currentRowAtIndexPath
// animated : NO
// scrollPosition : UITableViewScrollPositionNone ] ;
2020-09-21 20:33:31 -07:00
if ( self . notifier . pendingHide ) {
[ self hideNotifier ] ;
}
2012-08-02 18:00:48 -07:00
}
2013-06-19 20:26:04 -07:00
2018-08-29 14:55:37 -07:00
if ( self . searchFeedIds ) {
2018-11-21 13:31:50 -08:00
// [ self . feedTitlesTable setContentOffset : CGPointMake ( 0 , 0 ) ] ;
2018-08-29 14:55:37 -07:00
[ self . searchBar becomeFirstResponder ] ;
} else {
[ self . searchBar setText : @ "" ] ;
2018-11-21 13:31:50 -08:00
// [ self . feedTitlesTable setContentOffset : CGPointMake ( 0 , CGRectGetHeight ( self . searchBar . frame ) ) ] ;
2018-08-29 14:55:37 -07:00
}
[ self . searchBar setShowsCancelButton : self . searchBar . text . length > 0 animated : YES ] ;
2014-09-26 18:35:40 -07:00
// NSLog ( @ "Feed List timing 2: %f" , [ NSDate timeIntervalSinceReferenceDate ] - start ) ;
2010-06-25 18:36:01 -04:00
}
2010-06-21 17:17:26 -04:00
- ( void ) viewDidAppear : ( BOOL ) animated {
2011-08-24 21:44:16 -07:00
[ super viewDidAppear : animated ] ;
2014-02-21 16:06:49 -08:00
// self . navigationController . navigationBar . backItem . title = @ "All Sites" ;
2016-10-05 21:03:32 -07:00
[ self layoutHeaderCounts : 0 ] ;
2015-11-04 20:06:46 -08:00
[ self refreshHeaderCounts ] ;
2021-05-21 20:57:06 -07:00
if ( self . appDelegate . isCompactWidth ) {
[ self performSelector : @ selector ( fadeSelectedCell ) withObject : self afterDelay : 0.2 ] ;
2022-03-07 19:47:44 -07:00
[ self performSelector : @ selector ( fadeSelectedHeader ) withObject : nil afterDelay : 0.2 ] ;
2021-05-21 20:57:06 -07:00
self . currentRowAtIndexPath = nil ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
} else {
[ self highlightSelection ] ;
2021-05-21 20:57:06 -07:00
}
2013-12-10 18:14:32 -08:00
self . interactiveFeedDetailTransition = NO ;
2015-11-22 20:09:37 -05:00
[ self becomeFirstResponder ] ;
2013-12-10 18:14:32 -08:00
}
2021-04-24 21:55:36 -07:00
// - ( void ) handleGesture : ( UIScreenEdgePanGestureRecognizer * ) gesture {
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] ! = UIUserInterfaceIdiomPad ) return ;
//
// self . interactiveFeedDetailTransition = YES ;
//
// CGPoint point = [ gesture locationInView : self . view ] ;
// CGFloat viewWidth = CGRectGetWidth ( self . view . frame ) ;
// CGFloat percentage = MIN ( point . x , viewWidth ) / viewWidth ;
// // NSLog ( @ "back gesture: %d, %f - %f/%f" , ( int ) gesture . state , percentage , point . x , viewWidth ) ;
//
// if ( gesture . state = = UIGestureRecognizerStateBegan ) {
// // if ( appDelegate . storiesCollection . transferredFromDashboard ) {
// // [ appDelegate . dashboardViewController . storiesModule . storiesCollection
// // transferStoriesFromCollection : appDelegate . storiesCollection ] ;
// // [ appDelegate . dashboardViewController . storiesModule fadeSelectedCell : NO ] ;
// // }
// } else if ( gesture . state = = UIGestureRecognizerStateChanged ) {
// [ appDelegate . masterContainerViewController interactiveTransitionFromFeedDetail : percentage ] ;
// } else if ( gesture . state = = UIGestureRecognizerStateEnded ) {
// CGPoint velocity = [ gesture velocityInView : self . view ] ;
// if ( velocity . x > 0 ) {
// [ appDelegate . masterContainerViewController transitionFromFeedDetail ] ;
// } else {
// // // Returning back to view , cancelling pop animation .
// // [ appDelegate . masterContainerViewController transitionToFeedDetail : NO ] ;
2020-08-29 21:19:32 -07:00
// }
2021-04-24 21:55:36 -07:00
//
// self . interactiveFeedDetailTransition = NO ;
// }
// }
2012-07-27 19:42:19 -07:00
- ( void ) fadeSelectedCell {
2020-08-29 21:19:32 -07:00
[ self fadeCellWithIndexPath : [ self . feedTitlesTable indexPathForSelectedRow ] ] ;
}
- ( void ) fadeCellWithIndexPath : ( NSIndexPath * ) indexPath {
2014-09-22 16:46:07 -07:00
if ( ! indexPath ) return ;
2019-09-27 15:46:21 -07:00
[ self tableView : self . feedTitlesTable deselectRowAtIndexPath : indexPath animated : YES ] ;
2014-09-22 16:46:07 -07:00
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
id feedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : indexPath . row ] ;
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2014-03-04 18:09:43 -08:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
2014-09-22 16:46:07 -07:00
// NSLog ( @ "Show feeds after being read (%@): %d / %@ -> %@" , feedIdStr , [ preferences boolForKey : @ "show_feeds_after_being_read" ] , [ self . stillVisibleFeeds objectForKey : feedIdStr ] , self . stillVisibleFeeds ) ;
NSIndexPath * visiblePath = [ self . stillVisibleFeeds objectForKey : feedIdStr ] ;
if ( visiblePath ) {
2014-03-04 18:09:43 -08:00
[ self . feedTitlesTable beginUpdates ] ;
2014-09-22 18:02:25 -07:00
NSMutableArray * paths = ( indexPath . section = = visiblePath . section &&
indexPath . row = = visiblePath . row )
? @ [ indexPath ] . mutableCopy
: @ [ indexPath , visiblePath ] . mutableCopy ;
2014-09-22 16:46:07 -07:00
if ( ! [ preferences boolForKey : @ "show_feeds_after_being_read" ] ) {
[ self . stillVisibleFeeds removeObjectForKey : feedIdStr ] ;
for ( NSString * feedId in [ self . stillVisibleFeeds allKeys ] ) {
NSLog ( @ "Found inadvertantly still visible feed: %@" , feedId ) ;
[ paths addObject : [ self . stillVisibleFeeds objectForKey : feedId ] ] ;
}
}
[ self . feedTitlesTable reloadRowsAtIndexPaths : paths
2014-03-04 18:09:43 -08:00
withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . feedTitlesTable endUpdates ] ;
2014-09-24 12:37:13 -07:00
if ( ! [ preferences boolForKey : @ "show_feeds_after_being_read" ] ) {
[ self . stillVisibleFeeds removeAllObjects ] ;
}
2014-03-04 18:09:43 -08:00
}
2010-06-21 17:17:26 -04:00
}
2012-07-31 15:57:56 -07:00
2014-03-21 16:23:51 -07:00
- ( void ) fadeFeed : ( id ) feedId {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2019-09-27 15:46:21 -07:00
[ self tableView : self . feedTitlesTable deselectRowAtIndexPath : [ self . feedTitlesTable indexPathForSelectedRow ] animated : YES ] ;
2017-12-15 18:10:04 -08:00
for ( NSIndexPath * indexPath in [ self . feedTitlesTable indexPathsForVisibleRows ] ) {
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
id cellFeedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : indexPath . row ] ;
if ( [ feedIdStr isEqualToString : [ NSString stringWithFormat : @ "%@" , cellFeedId ] ] ) {
[ self . feedTitlesTable beginUpdates ] ;
[ self . feedTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . feedTitlesTable endUpdates ] ;
break ;
2014-03-21 16:23:51 -07:00
}
}
}
2010-06-21 17:17:26 -04:00
- ( void ) viewWillDisappear : ( BOOL ) animated {
2015-12-15 12:37:18 -08:00
[ self . appDelegate hidePopoverAnimated : YES ] ;
2012-06-19 14:27:35 -07:00
[ super viewWillDisappear : animated ] ;
2018-08-29 14:55:37 -07:00
[ self . searchBar resignFirstResponder ] ;
}
- ( void ) viewDidDisappear : ( BOOL ) animated {
[ super viewDidDisappear : animated ] ;
[ self . searchBar resignFirstResponder ] ;
2012-06-19 14:27:35 -07:00
}
2015-09-22 17:15:50 -07:00
- ( void ) viewWillTransitionToSize : ( CGSize ) size withTransitionCoordinator : ( id < UIViewControllerTransitionCoordinator > ) coordinator {
[ super viewWillTransitionToSize : size withTransitionCoordinator : coordinator ] ;
[ coordinator animateAlongsideTransition : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2015-09-22 17:15:50 -07:00
[ self layoutForInterfaceOrientation : orientation ] ;
[ self . notifier setNeedsLayout ] ;
} completion : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2015-09-22 17:15:50 -07:00
} ] ;
2012-07-20 22:00:30 -07:00
}
2013-10-03 13:54:15 -07:00
- ( void ) layoutForInterfaceOrientation : ( UIInterfaceOrientation ) interfaceOrientation {
2017-09-27 12:19:58 -07:00
// CGSize toolbarSize = [ self . feedViewToolbar sizeThatFits : self . view . frame . size ] ;
2020-03-29 16:21:00 -07:00
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
2017-09-27 12:19:58 -07:00
// self . feedViewToolbar . frame = CGRectMake ( -10.0 f ,
// CGRectGetHeight ( self . view . frame ) - toolbarSize . height ,
// toolbarSize . width + 20 , toolbarSize . height ) ;
// } else {
// self . feedViewToolbar . frame = ( CGRect ) { CGPointMake ( 0. f , CGRectGetHeight ( self . view . frame ) - toolbarSize . height ) , toolbarSize } ;
// }
// self . innerView . frame = ( CGRect ) { CGPointZero , CGSizeMake ( CGRectGetWidth ( self . view . frame ) , CGRectGetMinY ( self . feedViewToolbar . frame ) ) } ;
2019-07-25 15:31:27 -07:00
2020-08-29 21:19:32 -07:00
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad && ! appDelegate . isCompactWidth ) {
// CGRect navFrame = appDelegate . navigationController . view . frame ;
// CGFloat limit = appDelegate . masterContainerViewController . rightBorder . frame . origin . x + 1 ;
//
// if ( navFrame . size . width > limit ) {
// navFrame . size . width = limit ;
// appDelegate . navigationController . view . frame = navFrame ;
// }
// }
2019-07-25 15:31:27 -07:00
2017-10-12 21:49:45 -07:00
self . notifier . offset = CGPointMake ( 0 , 0 ) ;
2013-06-19 20:26:04 -07:00
2016-03-26 21:27:25 -07:00
[ self updateIntelligenceControlForOrientation : interfaceOrientation ] ;
2013-10-17 17:23:52 -07:00
[ self layoutHeaderCounts : interfaceOrientation ] ;
[ self refreshHeaderCounts ] ;
2013-02-27 19:25:57 -08:00
}
2010-06-20 11:04:23 -04:00
2016-03-26 21:27:25 -07:00
- ( void ) updateIntelligenceControlForOrientation : ( UIInterfaceOrientation ) orientation {
if ( orientation = = UIInterfaceOrientationUnknown ) {
2020-09-25 20:31:01 -07:00
orientation = self . view . window . windowScene . interfaceOrientation ;
2016-03-26 21:27:25 -07:00
}
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad && ! UIInterfaceOrientationIsLandscape ( orientation ) ) {
2016-03-26 21:27:25 -07:00
[ self . intelligenceControl setImage : [ UIImage imageNamed : @ "unread_yellow_icn.png" ] forSegmentAtIndex : 1 ] ;
2022-08-17 21:48:20 -07:00
[ self . intelligenceControl setImage : [ Utilities imageNamed : @ "indicator-focus" sized : 14 ] forSegmentAtIndex : 2 ] ;
2022-10-20 08:35:49 -04:00
[ self . intelligenceControl setImage : [ Utilities imageNamed : @ "unread_blue_icn.png" sized : 14 ] forSegmentAtIndex : 3 ] ;
2016-03-26 21:27:25 -07:00
[ self . intelligenceControl setWidth : 45 forSegmentAtIndex : 0 ] ;
[ self . intelligenceControl setWidth : 40 forSegmentAtIndex : 1 ] ;
[ self . intelligenceControl setWidth : 40 forSegmentAtIndex : 2 ] ;
[ self . intelligenceControl setWidth : 40 forSegmentAtIndex : 3 ] ;
} else {
[ self . intelligenceControl setImage : [ UIImage imageNamed : @ "unread_yellow.png" ] forSegmentAtIndex : 1 ] ;
2022-10-20 08:35:49 -04:00
[ self . intelligenceControl setImage : [ UIImage imageNamed : @ "unread_green.png" ] forSegmentAtIndex : 2 ] ;
[ self . intelligenceControl setImage : [ UIImage imageNamed : @ "unread_blue.png" ] forSegmentAtIndex : 3 ] ;
2016-03-26 21:27:25 -07:00
2017-05-05 20:29:44 -07:00
[ self . intelligenceControl setWidth : 40 forSegmentAtIndex : 0 ] ;
2016-03-26 21:27:25 -07:00
[ self . intelligenceControl setWidth : 68 forSegmentAtIndex : 1 ] ;
[ self . intelligenceControl setWidth : 62 forSegmentAtIndex : 2 ] ;
2017-05-05 20:29:44 -07:00
[ self . intelligenceControl setWidth : 60 forSegmentAtIndex : 3 ] ;
2016-03-26 21:27:25 -07:00
}
[ self . intelligenceControl sizeToFit ] ;
2017-09-27 12:19:58 -07:00
// NSInteger height = 16 ;
2020-03-29 16:21:00 -07:00
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone && UIInterfaceOrientationIsLandscape ( orientation ) ) {
2017-09-27 12:19:58 -07:00
// height = 8 ;
// }
//
// CGRect intelFrame = self . intelligenceControl . frame ;
// intelFrame . origin . x = ( self . feedViewToolbar . frame . size . width / 2 ) - ( intelFrame . size . width / 2 ) + 20 ;
// intelFrame . size . height = self . feedViewToolbar . frame . size . height - height ;
// self . intelligenceControl . frame = intelFrame ;
2016-03-26 21:27:25 -07:00
}
2015-11-22 20:09:37 -05:00
// allow keyboard comands
- ( BOOL ) canBecomeFirstResponder {
return YES ;
}
2010-06-20 11:04:23 -04:00
2019-03-22 20:55:22 -07:00
# pragma mark -
# pragma mark State Restoration
- ( void ) encodeRestorableStateWithCoder : ( NSCoder * ) coder {
[ super encodeRestorableStateWithCoder : coder ] ;
}
- ( void ) decodeRestorableStateWithCoder : ( NSCoder * ) coder {
[ super decodeRestorableStateWithCoder : coder ] ;
}
2010-06-20 11:04:23 -04:00
# pragma mark -
# pragma mark Initialization
2022-02-16 16:09:21 -08:00
- ( void ) leavingApp {
self . leftAppDate = [ NSDate date ] ;
}
2011-08-18 21:48:30 -07:00
- ( void ) returnToApp {
2018-04-06 09:53:00 -04:00
NSDate * decayDate = [ [ NSDate alloc ] initWithTimeIntervalSinceNow : ( -1 * BACKGROUND_REFRESH _SECONDS ) ] ;
2022-02-16 16:09:21 -08:00
NSLog ( @ "Left app: %@ - %f" , self . leftAppDate , [ self . leftAppDate timeIntervalSinceDate : decayDate ] ) ;
if ( [ self . leftAppDate timeIntervalSinceDate : decayDate ] < 0 ) {
2013-10-11 17:46:09 -07:00
[ appDelegate reloadFeedsView : YES ] ;
2011-08-24 21:44:16 -07:00
}
2011-08-18 21:48:30 -07:00
}
2012-08-09 10:18:15 -07:00
- ( void ) fetchFeedList : ( BOOL ) showLoader {
2017-03-23 17:37:58 -07:00
NSString * urlFeedList ;
2015-09-22 17:15:50 -07:00
NSLog ( @ "Fetching feed list" ) ;
2013-08-12 11:59:07 -07:00
[ appDelegate cancelOfflineQueue ] ;
2012-08-16 20:10:50 -07:00
if ( self . inPullToRefresh_ ) {
2020-06-15 19:57:06 -07:00
urlFeedList = [ NSString stringWithFormat : @ "%@/reader/feeds?flat=true&update_counts=true&include_inactive=true" ,
self . appDelegate . url ] ;
2012-08-16 20:10:50 -07:00
} else {
2020-06-15 19:57:06 -07:00
urlFeedList = [ NSString stringWithFormat : @ "%@/reader/feeds?flat=true&update_counts=false&include_inactive=true" ,
self . appDelegate . url ] ;
2013-10-11 18:16:37 -07:00
}
2011-08-24 21:44:16 -07:00
2022-11-09 21:14:39 -07:00
if ( appDelegate . backgroundAppRefreshTask ) {
2017-04-04 13:36:20 -07:00
urlFeedList = [ urlFeedList stringByAppendingString : @ "&background_ios=true" ] ;
}
2013-06-20 10:28:49 -07:00
2019-08-22 12:03:39 -07:00
[ appDelegate GET : urlFeedList parameters : nil success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-03-23 17:37:58 -07:00
[ self finishLoadingFeedList : responseObject ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
NSHTTPURLResponse * httpResponse = ( NSHTTPURLResponse * ) task . response ;
[ self finishedWithError : error statusCode : httpResponse . statusCode ] ;
} ] ;
2014-02-27 14:49:33 -08:00
2013-10-11 18:16:37 -07:00
if ( showLoader ) {
2017-04-04 13:36:20 -07:00
// [ self . notifier hide ] ;
2014-02-27 14:49:33 -08:00
}
2013-07-15 15:36:25 -07:00
[ self showRefreshNotifier ] ;
2010-11-13 13:42:20 -05:00
}
2017-03-23 17:37:58 -07:00
- ( void ) finishedWithError : ( NSError * ) error statusCode : ( NSInteger ) statusCode {
2017-06-01 21:19:54 -07:00
[ self finishRefresh ] ;
2017-03-23 17:37:58 -07:00
if ( statusCode = = 403 ) {
2015-09-22 17:15:50 -07:00
NSLog ( @ "Showing login" ) ;
2011-11-30 09:38:31 -08:00
return [ appDelegate showLogin ] ;
2017-03-23 17:37:58 -07:00
} else if ( statusCode >= 400 ) {
if ( statusCode = = 429 ) {
2013-06-20 10:28:49 -07:00
[ self informError : @ "Slow down. You're rate-limited." ] ;
2017-03-23 17:37:58 -07:00
} else if ( statusCode = = 503 ) {
2013-06-20 10:28:49 -07:00
[ self informError : @ "In maintenance mode" ] ;
} else {
[ self informError : @ "The server barfed!" ] ;
2013-04-29 11:38:06 -07:00
}
2013-06-20 10:28:49 -07:00
2014-02-18 16:44:41 -08:00
self . isOffline = YES ;
2022-01-27 20:06:50 -08:00
appDelegate . tryFeedStoryId = nil ;
appDelegate . inFindingStoryMode = NO ;
appDelegate . findingStoryStartDate = nil ;
2013-06-20 10:28:49 -07:00
[ self showOfflineNotifier ] ;
2014-02-27 14:49:33 -08:00
2013-06-20 10:28:49 -07:00
return ;
2011-09-05 22:06:31 -07:00
}
2017-03-23 17:37:58 -07:00
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
// User clicking on another link before the page loads is OK .
[ self informError : error ] ;
2011-09-05 22:06:31 -07:00
2017-03-23 17:37:58 -07:00
self . isOffline = YES ;
[ self showOfflineNotifier ] ;
[ self loadNotificationStory ] ;
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "FinishedLoadingFeedsNotification" object : nil ] ;
}
- ( void ) finishLoadingFeedList : ( NSDictionary * ) results {
2012-10-02 15:39:18 -07:00
appDelegate . hasNoSites = NO ;
2014-02-20 14:52:27 -08:00
appDelegate . recentlyReadStories = [ NSMutableDictionary dictionary ] ;
2014-03-05 15:20:31 -08:00
appDelegate . unreadStoryHashes = [ NSMutableDictionary dictionary ] ;
2018-09-13 10:44:00 -07:00
appDelegate . unsavedStoryHashes = [ NSMutableDictionary dictionary ] ;
2013-06-20 20:38:40 -07:00
self . isOffline = NO ;
2013-07-19 17:20:39 -07:00
appDelegate . activeUsername = [ results objectForKey : @ "user" ] ;
2015-09-30 17:18:18 -07:00
2022-01-26 21:37:41 -08:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
NSString * preview = [ userPreferences stringForKey : @ "story_list_preview_images_size" ] ;
2015-11-05 11:39:17 -08:00
NSUserDefaults * defaults = [ [ NSUserDefaults alloc ] initWithSuiteName : @ "group.com.newsblur.NewsBlur-Group" ] ;
2015-12-12 09:49:42 -08:00
[ defaults setObject : [ results objectForKey : @ "share_ext_token" ] forKey : @ "share:token" ] ;
2019-12-20 19:09:20 -08:00
[ defaults setObject : self . appDelegate . url forKey : @ "share:host" ] ;
2021-07-21 21:11:39 -07:00
[ defaults setObject : appDelegate . dictSavedStoryTags forKey : @ "share:tags" ] ;
2021-12-23 16:18:26 -07:00
[ defaults setObject : appDelegate . dictFoldersArray forKey : @ "share:folders" ] ;
2022-01-26 21:37:41 -08:00
[ defaults setObject : preview forKey : @ "widget:preview_images_size" ] ;
2019-12-20 19:09:20 -08:00
[ self validateWidgetFeedsForGroupDefaults : defaults usingResults : results ] ;
2015-09-30 17:18:18 -07:00
[ defaults synchronize ] ;
2019-12-20 19:09:20 -08:00
2013-10-17 17:23:52 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
2020-08-27 15:08:46 -07:00
[ self . appDelegate . database inTransaction : ^ ( FMDatabase * db , BOOL * rollback ) {
[ db executeUpdate : @ "DELETE FROM accounts WHERE username = ?" , self . appDelegate . activeUsername ] ;
2013-10-17 17:23:52 -07:00
[ db executeUpdate : @ "INSERT INTO accounts"
"(username, download_date, feeds_json) VALUES "
"(?, ?, ?)" ,
2020-08-27 15:08:46 -07:00
self . appDelegate . activeUsername ,
2013-10-17 17:23:52 -07:00
[ NSDate date ] ,
[ results JSONRepresentation ]
] ;
for ( NSDictionary * feed in [ results objectForKey : @ "social_feeds" ] ) {
[ db executeUpdate : @ "INSERT INTO unread_counts (feed_id, ps, nt, ng) VALUES "
"(?, ?, ?, ?)" ,
[ feed objectForKey : @ "id" ] ,
[ feed objectForKey : @ "ps" ] ,
[ feed objectForKey : @ "nt" ] ,
[ feed objectForKey : @ "ng" ] ] ;
}
for ( NSString * feedId in [ results objectForKey : @ "feeds" ] ) {
NSDictionary * feed = [ [ results objectForKey : @ "feeds" ] objectForKey : feedId ] ;
[ db executeUpdate : @ "INSERT INTO unread_counts (feed_id, ps, nt, ng) VALUES "
"(?, ?, ?, ?)" ,
[ feed objectForKey : @ "id" ] ,
[ feed objectForKey : @ "ps" ] ,
[ feed objectForKey : @ "nt" ] ,
[ feed objectForKey : @ "ng" ] ] ;
}
} ] ;
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2014-02-27 14:49:33 -08:00
[ self finishLoadingFeedListWithDict : results finished : YES ] ;
2013-10-17 17:23:52 -07:00
} ) ;
} ) ;
2013-06-20 19:25:57 -07:00
}
2014-02-27 14:49:33 -08:00
- ( void ) finishLoadingFeedListWithDict : ( NSDictionary * ) results finished : ( BOOL ) finished {
2013-06-20 19:25:57 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2012-10-17 15:07:53 -07:00
2018-11-21 13:31:50 -08:00
// Doing this here avoids the search bar from appearing on initial load , but doesn ' t help when only a few rows visible .
// if ( ! self . searchFeedIds && self . feedTitlesTable . contentOffset . y = = 0 ) {
// self . feedTitlesTable . contentOffset = CGPointMake ( 0 , CGRectGetHeight ( self . searchBar . frame ) ) ;
// }
2011-08-24 21:44:16 -07:00
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
self . stillVisibleFeeds = [ NSMutableDictionary dictionary ] ;
2012-06-26 11:45:42 -07:00
2011-09-05 22:06:31 -07:00
appDelegate . activeUsername = [ results objectForKey : @ "user" ] ;
2013-07-19 17:20:39 -07:00
if ( appDelegate . activeUsername ) {
[ userPreferences setObject : appDelegate . activeUsername forKey : @ "active_username" ] ;
[ userPreferences synchronize ] ;
}
2012-08-11 18:03:28 -07:00
2013-10-03 13:54:15 -07:00
// Bottom toolbar
2017-09-27 12:19:58 -07:00
// UIImage * addImage = [ UIImage imageNamed : @ "nav_icn_add.png" ] ;
// UIImage * settingsImage = [ UIImage imageNamed : @ "nav_icn_settings.png" ] ;
// addBarButton . enabled = YES ;
2015-11-04 20:06:46 -08:00
addBarButton . accessibilityLabel = @ "Add site" ;
2017-09-27 12:19:58 -07:00
// settingsBarButton . enabled = YES ;
2015-11-04 20:06:46 -08:00
settingsBarButton . accessibilityLabel = @ "Settings" ;
2017-09-27 12:19:58 -07:00
// NBBarButtonItem * addButton = [ NBBarButtonItem buttonWithType : UIButtonTypeCustom ] ;
// [ addButton setImage : [ [ ThemeManager themeManager ] themedImage : addImage ] forState : UIControlStateNormal ] ;
// [ addButton sizeToFit ] ;
// [ addButton addTarget : self action : @ selector ( tapAddSite : )
// forControlEvents : UIControlEventTouchUpInside ] ;
// addButton . accessibilityLabel = @ "Add feed" ;
// [ addBarButton setCustomView : addButton ] ;
// NBBarButtonItem * settingsButton = [ NBBarButtonItem buttonWithType : UIButtonTypeCustom ] ;
// settingsButton . onRightSide = YES ;
// [ settingsButton setImage : [ [ ThemeManager themeManager ] themedImage : settingsImage ] forState : UIControlStateNormal ] ;
// [ settingsButton sizeToFit ] ;
// [ settingsButton addTarget : self action : @ selector ( showSettingsPopover : )
// forControlEvents : UIControlEventTouchUpInside ] ;
// settingsButton . accessibilityLabel = @ "Settings" ;
// [ settingsBarButton setCustomView : settingsButton ] ;
2013-02-22 12:13:01 -08:00
2022-08-17 21:48:20 -07:00
UIImage * activityImage = [ Utilities templateImageNamed : @ "dialog-notifications" sized : 32 ] ;
2020-08-29 21:19:32 -07:00
NBBarButtonItem * activityButton = [ NBBarButtonItem buttonWithType : UIButtonTypeCustom ] ;
activityButton . accessibilityLabel = @ "Activities" ;
[ activityButton setImage : activityImage forState : UIControlStateNormal ] ;
2022-08-17 21:48:20 -07:00
activityButton . tintColor = UIColorFromRGB ( 0 x8F918B ) ;
2022-10-26 13:20:36 -06:00
[ activityButton setImageEdgeInsets : UIEdgeInsetsMake ( 4 , 0 , 4 , 0 ) ] ;
2020-08-29 21:19:32 -07:00
[ activityButton addTarget : self
action : @ selector ( showInteractionsPopover : )
forControlEvents : UIControlEventTouchUpInside ] ;
activitiesButton = [ [ UIBarButtonItem alloc ]
initWithCustomView : activityButton ] ;
activitiesButton . width = 32 ;
2022-10-26 13:20:36 -06:00
// activityButton . backgroundColor = UIColor . redColor ;
2020-08-29 21:19:32 -07:00
self . navigationItem . rightBarButtonItem = activitiesButton ;
2012-07-12 11:35:32 -07:00
2011-09-05 22:06:31 -07:00
NSMutableDictionary * sortedFolders = [ [ NSMutableDictionary alloc ] init ] ;
2011-10-14 17:15:48 -07:00
NSArray * sortedArray ;
2011-09-05 22:06:31 -07:00
2013-03-04 20:21:29 -08:00
// Set up dictSocialProfile and userActivitiesArray
2014-05-20 12:21:17 -07:00
appDelegate . dictUnreadCounts = [ NSMutableDictionary dictionary ] ;
2013-03-04 20:21:29 -08:00
appDelegate . dictSocialProfile = [ results objectForKey : @ "social_profile" ] ;
appDelegate . dictUserProfile = [ results objectForKey : @ "user_profile" ] ;
appDelegate . dictSocialServices = [ results objectForKey : @ "social_services" ] ;
2012-07-26 23:07:47 -07:00
appDelegate . userActivitiesArray = [ results objectForKey : @ "activities" ] ;
2012-08-11 18:03:28 -07:00
2017-11-09 18:43:37 -08:00
appDelegate . isPremium = [ [ appDelegate . dictUserProfile objectForKey : @ "is_premium" ] integerValue ] = = 1 ;
2022-06-22 21:35:54 -06:00
appDelegate . isPremiumArchive = [ [ appDelegate . dictUserProfile objectForKey : @ "is_archive" ] integerValue ] = = 1 ;
2017-11-10 17:37:31 -08:00
id premiumExpire = [ appDelegate . dictUserProfile objectForKey : @ "premium_expire" ] ;
2017-11-15 11:14:05 -08:00
if ( premiumExpire && ! [ premiumExpire isKindOfClass : [ NSNull class ] ] && premiumExpire ! = 0 ) {
appDelegate . premiumExpire = [ premiumExpire integerValue ] ;
2017-11-10 17:37:31 -08:00
}
2018-10-04 16:59:07 -07:00
if ( ! appDelegate . premiumManager ) {
appDelegate . premiumManager = [ PremiumManager new ] ;
}
2012-06-26 12:29:37 -07:00
// Set up dictSocialFeeds
2012-06-26 11:45:42 -07:00
NSArray * socialFeedsArray = [ results objectForKey : @ "social_feeds" ] ;
2012-06-25 15:02:20 -07:00
NSMutableArray * socialFolder = [ [ NSMutableArray alloc ] init ] ;
NSMutableDictionary * socialDict = [ [ NSMutableDictionary alloc ] init ] ;
2012-07-15 15:06:06 -07:00
NSMutableDictionary * tempActiveFeeds = [ [ NSMutableDictionary alloc ] init ] ;
appDelegate . dictActiveFeeds = tempActiveFeeds ;
2012-06-25 15:02:20 -07:00
2012-06-26 11:45:42 -07:00
for ( int i = 0 ; i < socialFeedsArray . count ; i + + ) {
2012-06-25 15:02:20 -07:00
NSString * userKey = [ NSString stringWithFormat : @ "%@" ,
2012-06-26 11:45:42 -07:00
[ [ socialFeedsArray objectAtIndex : i ] objectForKey : @ "id" ] ] ;
[ socialFolder addObject : [ [ socialFeedsArray objectAtIndex : i ] objectForKey : @ "id" ] ] ;
[ socialDict setObject : [ socialFeedsArray objectAtIndex : i ]
2012-06-25 15:02:20 -07:00
forKey : userKey ] ;
}
2012-07-01 18:26:39 -07:00
2012-06-25 15:02:20 -07:00
appDelegate . dictSocialFeeds = socialDict ;
2012-07-10 16:48:05 -07:00
2012-06-26 12:29:37 -07:00
// set up dictFolders
2012-08-02 19:43:55 -07:00
NSMutableDictionary * allFolders = [ [ NSMutableDictionary alloc ] init ] ;
2020-06-15 19:57:06 -07:00
if ( ! [ [ results objectForKey : @ "flat_folders_with_inactive" ] isKindOfClass : [ NSArray class ] ] ) {
allFolders = [ [ results objectForKey : @ "flat_folders_with_inactive" ] mutableCopy ] ;
2012-08-02 19:43:55 -07:00
}
2020-06-15 19:57:06 -07:00
2021-04-23 13:39:37 -07:00
[ self fixFolderNames : allFolders ] ;
2012-10-03 15:46:02 -07:00
[ allFolders setValue : socialFolder forKey : @ "river_blurblogs" ] ;
2012-12-07 15:17:22 -08:00
[ allFolders setValue : [ [ NSMutableArray alloc ] init ] forKey : @ "river_global" ] ;
2020-05-27 21:26:44 -07:00
NSArray * savedSearches = [ appDelegate updateSavedSearches : results ] ;
[ allFolders setValue : savedSearches forKey : @ "saved_searches" ] ;
2014-11-04 17:53:27 -08:00
NSArray * savedStories = [ appDelegate updateStarredStoryCounts : results ] ;
[ allFolders setValue : savedStories forKey : @ "saved_stories" ] ;
2012-06-26 12:29:37 -07:00
appDelegate . dictFolders = allFolders ;
2020-06-15 19:57:06 -07:00
appDelegate . dictInactiveFeeds = [ results [ @ "inactive_feeds" ] mutableCopy ] ;
2012-06-26 12:29:37 -07:00
// set up dictFeeds
2012-07-27 16:10:13 -07:00
appDelegate . dictFeeds = [ [ results objectForKey : @ "feeds" ] mutableCopy ] ;
2020-06-15 19:57:06 -07:00
[ appDelegate . dictFeeds addEntriesFromDictionary : appDelegate . dictInactiveFeeds ] ;
2013-06-29 17:28:41 -07:00
[ appDelegate populateDictUnreadCounts ] ;
2015-11-04 20:06:46 -08:00
[ appDelegate populateDictTextFeeds ] ;
2013-06-29 17:28:41 -07:00
2019-08-24 15:06:50 -07:00
NSString * sortOrder = [ userPreferences stringForKey : @ "feed_list_sort_order" ] ;
BOOL sortByMostUsed = [ sortOrder isEqualToString : @ "usage" ] ;
NSMutableArray * sortDescriptors = [ NSMutableArray array ] ;
if ( sortByMostUsed ) {
[ sortDescriptors addObject : [ NSSortDescriptor sortDescriptorWithKey : @ "feed_opens" ascending : NO ] ] ;
}
2021-04-23 15:12:03 -07:00
NSSortDescriptor * titleDescriptor = [ NSSortDescriptor sortDescriptorWithKey : @ "feed_title" ascending : YES comparator : ^ NSComparisonResult ( id _Nonnull obj1 , id _Nonnull obj2 ) {
return [ [ self sortableString : obj1 ] localizedStandardCompare : [ self sortableString : obj2 ] ] ;
} ] ;
[ sortDescriptors addObject : titleDescriptor ] ;
2019-08-24 15:06:50 -07:00
2012-06-26 12:29:37 -07:00
// sort all the folders
appDelegate . dictFoldersArray = [ NSMutableArray array ] ;
for ( id f in appDelegate . dictFolders ) {
NSArray * folder = [ appDelegate . dictFolders objectForKey : f ] ;
2012-10-14 17:33:07 -04:00
NSString * folderTitle ;
if ( [ f isEqualToString : @ " " ] ) {
folderTitle = @ "everything" ;
} else {
folderTitle = f ;
}
[ appDelegate . dictFoldersArray addObject : folderTitle ] ;
2019-08-24 15:06:50 -07:00
NSMutableArray * feeds = [ NSMutableArray array ] ;
for ( id feedId in folder ) {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2020-05-27 21:26:44 -07:00
NSDictionary * feed = nil ;
2012-06-26 12:29:37 -07:00
2020-06-11 21:02:22 -07:00
if ( [ appDelegate isSavedSearch : feedIdStr ] || [ appDelegate isSavedFeed : feedIdStr ] ) {
2019-08-24 15:06:50 -07:00
feed = @ { @ "id" : feedId } ;
} else if ( [ appDelegate isSocialFeed : feedIdStr ] ) {
feed = appDelegate . dictSocialFeeds [ feedIdStr ] ;
2012-06-26 12:29:37 -07:00
} else {
2019-08-24 15:06:50 -07:00
feed = appDelegate . dictFeeds [ feedIdStr ] ;
2012-06-26 12:29:37 -07:00
}
2019-08-24 15:06:50 -07:00
if ( feed ! = nil ) {
[ feeds addObject : feed ] ;
}
}
NSArray * sortedFeeds = [ feeds sortedArrayUsingDescriptors : sortDescriptors ] ;
sortedArray = [ sortedFeeds valueForKey : @ "id" ] ;
2012-10-14 17:33:07 -04:00
[ sortedFolders setValue : sortedArray forKey : folderTitle ] ;
2012-06-26 12:29:37 -07:00
}
2022-08-02 21:46:26 -07:00
2011-10-14 17:15:48 -07:00
appDelegate . dictFolders = sortedFolders ;
2011-10-04 18:01:35 -07:00
[ appDelegate . dictFoldersArray sortUsingSelector : @ selector ( caseInsensitiveCompare : ) ] ;
2022-08-02 21:46:26 -07:00
appDelegate . dictSubfolders = [ NSMutableDictionary dictionary ] ;
// Add feeds from subfolders
[ self addSubfolderFeeds ] ;
2022-07-08 21:29:43 -07:00
// Add all stories etc . to top
2018-01-28 11:08:38 -05:00
[ NewsBlurTopSectionNames enumerateObjectsUsingBlock : ^ ( NSString * _Nonnull sectionName , NSUInteger sectionIndex , BOOL * _Nonnull stop ) {
[ appDelegate . dictFoldersArray removeObject : sectionName ] ;
[ appDelegate . dictFoldersArray insertObject : sectionName atIndex : sectionIndex ] ;
} ] ;
2022-03-09 19:16:43 -07:00
// Add Widget Site Stories folder to bottom
2022-03-11 21:30:28 -07:00
// [ appDelegate . dictFoldersArray removeObject : @ "widget_stories" ] ;
// NSUserDefaults * groupDefaults = [ [ NSUserDefaults alloc ] initWithSuiteName : @ "group.com.newsblur.NewsBlur-Group" ] ;
// NSMutableArray * feeds = [ groupDefaults objectForKey : @ "widget:feeds_array" ] ;
// if ( feeds . count ) {
// [ appDelegate . dictFoldersArray insertObject : @ "widget_stories" atIndex : appDelegate . dictFoldersArray . count ] ;
// }
2022-03-09 19:16:43 -07:00
2018-01-28 11:08:38 -05:00
// Add Read Stories folder to bottom
2014-10-22 16:39:37 -07:00
[ appDelegate . dictFoldersArray removeObject : @ "read_stories" ] ;
2022-07-08 21:29:43 -07:00
[ appDelegate . dictFoldersArray addObject : @ "read_stories" ] ;
// Add Global Shared Stories folder to bottom
[ appDelegate . dictFoldersArray removeObject : @ "river_global" ] ;
[ appDelegate . dictFoldersArray addObject : @ "river_global" ] ;
// Add All Shared Stories folder to bottom
[ appDelegate . dictFoldersArray removeObject : @ "river_blurblogs" ] ;
[ appDelegate . dictFoldersArray addObject : @ "river_blurblogs" ] ;
2020-05-27 21:26:44 -07:00
// Add Saved Searches folder to bottom
[ appDelegate . dictFoldersArray removeObject : @ "saved_searches" ] ;
2020-06-11 21:02:22 -07:00
if ( appDelegate . savedSearchesCount ) {
2022-07-08 21:29:43 -07:00
[ appDelegate . dictFoldersArray addObject : @ "saved_searches" ] ;
2020-05-27 21:26:44 -07:00
}
2018-01-28 11:08:38 -05:00
// Add Saved Stories folder to bottom
2014-12-15 12:25:09 -08:00
[ appDelegate . dictFoldersArray removeObject : @ "saved_stories" ] ;
2012-10-17 15:07:53 -07:00
if ( appDelegate . savedStoriesCount ) {
2022-07-08 21:29:43 -07:00
[ appDelegate . dictFoldersArray addObject : @ "saved_stories" ] ;
2012-10-17 15:07:53 -07:00
}
2012-08-02 19:43:55 -07:00
2012-12-20 12:08:35 -08:00
// test for empty
2012-08-02 19:43:55 -07:00
if ( [ [ appDelegate . dictFeeds allKeys ] count ] = = 0 &&
[ [ appDelegate . dictSocialFeeds allKeys ] count ] = = 0 ) {
2012-10-02 15:39:18 -07:00
appDelegate . hasNoSites = YES ;
2012-08-02 19:43:55 -07:00
}
2012-12-20 12:08:35 -08:00
[ self calculateFeedLocations ] ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2013-02-15 16:41:20 -08:00
[ self refreshHeaderCounts ] ;
2012-06-27 10:04:44 -07:00
2013-06-29 17:28:41 -07:00
// assign categories for FTUX
2012-08-14 17:20:45 -07:00
if ( ! [ [ results objectForKey : @ "categories" ] isKindOfClass : [ NSNull class ] ] ) {
appDelegate . categories = [ [ results objectForKey : @ "categories" ] objectForKey : @ "categories" ] ;
appDelegate . categoryFeeds = [ [ results objectForKey : @ "categories" ] objectForKey : @ "feeds" ] ;
}
2011-09-05 22:06:31 -07:00
2013-06-20 20:38:40 -07:00
if ( ! self . isOffline ) {
2013-07-03 17:52:13 -07:00
// start up the first time user experience
if ( [ [ results objectForKey : @ "social_feeds" ] count ] = = 0 &&
[ [ [ results objectForKey : @ "feeds" ] allKeys ] count ] = = 0 ) {
[ appDelegate showFirstTimeUser ] ;
return ;
}
2018-04-06 09:53:00 -04:00
[ self showSyncingNotifier ] ;
[ self . appDelegate flushQueuedReadStories : YES withCallback : ^ {
[ self refreshFeedList ] ;
} ] ;
2012-08-16 20:10:50 -07:00
}
2012-08-12 16:50:34 -07:00
2012-08-15 19:31:34 -07:00
self . intelligenceControl . hidden = NO ;
2013-04-12 13:06:47 -07:00
[ self showExplainerOnEmptyFeedlist ] ;
2016-10-05 21:03:32 -07:00
[ self layoutHeaderCounts : 0 ] ;
2013-10-17 17:23:52 -07:00
[ self refreshHeaderCounts ] ;
2017-04-05 18:46:39 -07:00
[ appDelegate checkForFeedNotifications ] ;
2014-02-10 19:21:53 -08:00
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad && finished ) {
2017-12-15 18:10:04 -08:00
[ self cacheFeedRowLocations ] ;
2014-02-10 19:21:53 -08:00
}
2023-06-27 22:10:37 -07:00
2023-06-28 15:51:15 -07:00
if ( appDelegate . pendingFolder ! = nil ) {
if ( [ appDelegate splitUnreadCountForFolder : appDelegate . pendingFolder ] . nt > 0 ) {
[ self loadNotificationStory ] ;
}
} else {
2023-06-27 22:10:37 -07:00
[ self loadNotificationStory ] ;
}
2016-01-27 20:52:09 -08:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "FinishedLoadingFeedsNotification" object : nil ] ;
2015-09-23 22:47:03 -07:00
}
2013-06-20 10:28:49 -07:00
2021-04-23 15:12:03 -07:00
- ( NSString * ) sortableString : ( NSString * ) original {
NSString * string = original . lowercaseString ;
string = [ self stripPrefix : @ "the " fromString : string ] ;
string = [ self stripPrefix : @ "a " fromString : string ] ;
string = [ self stripPrefix : @ "an " fromString : string ] ;
return string ;
}
- ( NSString * ) stripPrefix : ( NSString * ) prefix fromString : ( NSString * ) original {
if ( [ original hasPrefix : prefix ] ) {
return [ original substringFromIndex : prefix . length ] ;
} else {
return original ;
}
}
2021-04-23 13:39:37 -07:00
- ( void ) fixFolderNames : ( NSMutableDictionary * ) folders {
for ( NSString * folderName in folders . copy ) {
if ( [ folderName containsString : @ " - " ] ) {
NSDictionary * folder = folders [ folderName ] ;
NSArray * components = [ folderName componentsSeparatedByString : @ " - " ] ;
2022-08-02 21:46:26 -07:00
NSMutableArray * parentComponents = [ components mutableCopy ] ;
[ parentComponents removeLastObject ] ;
NSString * rawParentName = [ parentComponents componentsJoinedByString : @ " - " ] ;
NSString * tidyParentName = [ parentComponents componentsJoinedByString : @ " ▸ " ] ;
2021-04-23 13:39:37 -07:00
NSString * tidyName = [ components componentsJoinedByString : @ " ▸ " ] ;
2022-08-02 21:46:26 -07:00
if ( folders [ rawParentName ] ! = nil || folders [ tidyParentName ] ! = nil ) {
2021-04-23 13:39:37 -07:00
folders [ folderName ] = nil ;
folders [ tidyName ] = folder ;
}
}
}
}
2017-12-15 18:10:04 -08:00
- ( void ) cacheFeedRowLocations {
indexPathsForFeedIds = [ NSMutableDictionary dictionary ] ;
dispatch_queue _t queue = dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _LOW , 0 ul ) ;
dispatch_async ( queue , ^ {
2020-08-27 15:08:46 -07:00
for ( NSString * folderName in self . appDelegate . dictFoldersArray ) {
NSInteger section = [ self . appDelegate . dictFoldersArray indexOfObject : folderName ] ;
NSArray * folder = [ self . appDelegate . dictFolders objectForKey : folderName ] ;
2017-12-15 18:10:04 -08:00
for ( NSInteger row = 0 ; row < folder . count ; row + + ) {
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : row inSection : section ] ;
2020-08-27 15:08:46 -07:00
[ self -> indexPathsForFeedIds setObject : indexPath forKey : [ folder objectAtIndex : row ] ] ;
2017-12-15 18:10:04 -08:00
}
}
} ) ;
}
2013-10-08 13:57:15 -07:00
- ( void ) loadOfflineFeeds : ( BOOL ) failed {
2013-06-20 19:25:57 -07:00
__block __typeof __ ( self ) _self = self ;
2013-06-20 20:38:40 -07:00
self . isOffline = YES ;
2015-09-22 17:15:50 -07:00
NSLog ( @ "Loading offline feeds: %d" , failed ) ;
2013-07-19 17:20:39 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
if ( ! appDelegate . activeUsername ) {
appDelegate . activeUsername = [ userPreferences stringForKey : @ "active_username" ] ;
2013-10-11 18:16:37 -07:00
if ( ! appDelegate . activeUsername ) {
if ( failed ) {
return ;
} else {
2013-10-17 17:23:52 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ self fetchFeedList : YES ] ;
} ) ;
2013-10-11 18:16:37 -07:00
return ;
}
}
2013-07-19 17:20:39 -07:00
}
2013-10-11 18:16:37 -07:00
[ self showRefreshNotifier ] ;
2013-07-19 17:20:39 -07:00
[ appDelegate . database inDatabase : ^ ( FMDatabase * db ) {
NSDictionary * results ;
FMResultSet * cursor = [ db executeQuery : @ "SELECT * FROM accounts WHERE username = ? LIMIT 1" ,
2020-08-27 15:08:46 -07:00
self . appDelegate . activeUsername ] ;
2013-07-19 17:20:39 -07:00
while ( [ cursor next ] ) {
NSDictionary * feedsCache = [ cursor resultDictionary ] ;
results = [ NSJSONSerialization
JSONObjectWithData : [ [ feedsCache objectForKey : @ "feeds_json" ]
dataUsingEncoding : NSUTF8StringEncoding ]
2016-10-05 21:03:32 -07:00
options : 0 error : nil ] ;
2013-07-19 17:20:39 -07:00
break ;
}
2013-10-03 18:07:39 -07:00
[ cursor close ] ;
2013-07-19 17:20:39 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2014-02-27 14:49:33 -08:00
[ _self finishLoadingFeedListWithDict : results finished : failed ] ;
2013-10-11 17:46:09 -07:00
[ _self fetchFeedList : NO ] ;
2013-07-19 17:20:39 -07:00
} ) ;
} ] ;
2013-06-20 10:28:49 -07:00
}
2016-12-06 16:03:40 -08:00
- ( void ) loadNotificationStory {
2021-01-16 19:36:16 -08:00
@ throw [ NSException exceptionWithName : @ "Missing loadNotificationStory implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
}
2022-08-02 21:46:26 -07:00
- ( void ) addSubfolderFeeds {
@ throw [ NSException exceptionWithName : @ "Missing addSubfolderFeeds implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
}
- ( NSString * ) parentTitleForFolderTitle : ( NSString * ) folderTitle {
@ throw [ NSException exceptionWithName : @ "Missing parentTitleForFolderTitle: implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
}
- ( NSArray < NSString * > * ) parentTitlesForFolderTitle : ( NSString * ) folderTitle {
@ throw [ NSException exceptionWithName : @ "Missing parentsTitlesForFolderTitle: implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
}
2012-07-25 17:29:29 -07:00
- ( void ) showUserProfile {
2013-03-04 20:21:29 -08:00
appDelegate . activeUserProfileId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
appDelegate . activeUserProfileName = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "username" ] ] ;
2012-08-09 10:18:15 -07:00
// appDelegate . activeUserProfileName = @ "You" ;
2020-10-30 20:58:27 -07:00
[ appDelegate showUserProfileModal : self . navigationItem . titleView ] ;
2012-07-12 00:10:42 -07:00
}
2012-07-31 15:57:56 -07:00
- ( IBAction ) tapAddSite : ( id ) sender {
2021-01-16 20:47:03 -08:00
// [ self . appDelegate . addSiteNavigationController popToRootViewControllerAnimated : NO ] ;
2021-04-22 21:49:13 -07:00
// [ self . splitViewController showColumn : UISplitViewControllerColumnPrimary ] ;
[ self . appDelegate showFeedsListAnimated : NO ] ;
2016-03-18 21:29:42 -07:00
2017-09-27 12:19:58 -07:00
[ self . appDelegate showPopoverWithViewController : self . appDelegate . addSiteNavigationController contentSize : CGSizeMake ( 320 , 96 ) barButtonItem : self . addBarButton ] ;
2016-03-18 21:29:42 -07:00
2015-12-15 12:37:18 -08:00
[ self . appDelegate . addSiteViewController reload ] ;
2012-07-31 15:57:56 -07:00
}
2013-02-20 17:00:01 -08:00
- ( IBAction ) showSettingsPopover : ( id ) sender {
2021-05-29 21:25:43 -07:00
if ( self . presentedViewController ) {
[ self . presentedViewController dismissViewControllerAnimated : YES completion : nil ] ;
return ;
}
MenuViewController * viewController = [ MenuViewController new ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ viewController addTitle : @ "Preferences" iconName : @ "dialog-preferences" iconColor : UIColorFromRGB ( 0 xDF8566 ) selectionShouldDismiss : YES handler : ^ {
2021-05-29 21:25:43 -07:00
[ self . appDelegate showPreferences ] ;
} ] ;
[ viewController addTitle : @ "Mute Sites" iconName : @ "menu_icn_mute.png" selectionShouldDismiss : YES handler : ^ {
[ self . appDelegate showMuteSites ] ;
} ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ viewController addTitle : @ "Organize Sites" iconName : @ "dialog-organize" iconColor : UIColorFromRGB ( 0 xDF8566 ) selectionShouldDismiss : YES handler : ^ {
2021-05-29 21:25:43 -07:00
[ self . appDelegate showOrganizeSites ] ;
} ] ;
2022-01-05 12:52:27 -05:00
[ viewController addTitle : @ "Widget Sites" iconName : @ "calendar.png" selectionShouldDismiss : YES handler : ^ {
2021-05-29 21:25:43 -07:00
[ self . appDelegate showWidgetSites ] ;
} ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ viewController addTitle : @ "Notifications" iconName : @ "dialog-notifications" iconColor : UIColorFromRGB ( 0 xD58B4F ) selectionShouldDismiss : YES handler : ^ {
2021-05-29 21:25:43 -07:00
[ self . appDelegate openNotificationsWithFeed : nil ] ;
} ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ viewController addTitle : @ "Find Friends" iconName : @ "followers" iconColor : UIColorFromRGB ( 0 x5FA1E7 ) selectionShouldDismiss : YES handler : ^ {
2021-05-29 21:25:43 -07:00
[ self . appDelegate showFindFriends ] ;
} ] ;
2022-06-22 21:35:54 -06:00
if ( appDelegate . isPremium && appDelegate . isPremiumArchive ) {
[ viewController addTitle : @ "Premium Archive" iconName : @ "g_icn_greensun.png" selectionShouldDismiss : YES handler : ^ {
[ self . appDelegate showPremiumDialog ] ;
} ] ;
} else if ( appDelegate . isPremium ) {
[ viewController addTitle : @ "Upgrade to Archive" iconName : @ "g_icn_greensun.png" selectionShouldDismiss : YES handler : ^ {
2021-05-29 21:25:43 -07:00
[ self . appDelegate showPremiumDialog ] ;
} ] ;
} else {
[ viewController addTitle : @ "Upgrade to Premium" iconName : @ "g_icn_greensun.png" selectionShouldDismiss : YES handler : ^ {
[ self . appDelegate showPremiumDialog ] ;
} ] ;
}
2022-01-05 12:30:44 -05:00
[ viewController addTitle : @ "Support Forum" iconName : @ "discourse.png" selectionShouldDismiss : YES handler : ^ {
2021-12-20 19:50:22 -07:00
NSURL * url = [ NSURL URLWithString : @ "https://forum.newsblur.com" ] ;
[ [ UIApplication sharedApplication ] openURL : url options : @ { } completionHandler : nil ] ;
} ] ;
2021-05-29 21:25:43 -07:00
[ viewController addTitle : @ "Logout" iconName : @ "menu_icn_fetch_subscribers.png" selectionShouldDismiss : YES handler : ^ {
[ self . appDelegate confirmLogout ] ;
} ] ;
if ( [ appDelegate . activeUsername isEqualToString : @ "samuel" ] || [ appDelegate . activeUsername isEqualToString : @ "Dejal" ] ) {
[ viewController addTitle : @ "Login as…" iconName : @ "barbutton_sendto.png" selectionShouldDismiss : YES handler : ^ {
[ self showLoginAsDialog ] ;
} ] ;
}
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] ! = UIUserInterfaceIdiomPhone ) {
[ appDelegate addSplitControlToMenuController : viewController ] ;
}
2015-12-15 12:37:18 -08:00
2021-05-29 21:25:43 -07:00
NSString * preferenceKey = @ "feed_list_font_size" ;
NSArray * titles = @ [ @ "XS" , @ "S" , @ "M" , @ "L" , @ "XL" ] ;
NSArray * values = @ [ @ "xs" , @ "small" , @ "medium" , @ "large" , @ "xl" ] ;
2022-08-03 21:42:28 -07:00
[ viewController addSegmentedControlWithTitles : titles values : values preferenceKey : preferenceKey selectionShouldDismiss : NO handler : ^ ( NSUInteger selectedIndex ) {
2021-05-29 21:25:43 -07:00
[ self . appDelegate resizeFontSize ] ;
} ] ;
2021-12-20 20:40:43 -07:00
preferenceKey = @ "feed_list_spacing" ;
titles = @ [ @ "Compact" , @ "Comfortable" ] ;
values = @ [ @ "compact" , @ "comfortable" ] ;
2022-08-03 21:42:28 -07:00
[ viewController addSegmentedControlWithTitles : titles values : values defaultValue : @ "comfortable" preferenceKey : preferenceKey selectionShouldDismiss : NO handler : ^ ( NSUInteger selectedIndex ) {
2021-12-20 20:40:43 -07:00
[ self reloadFeedTitlesTable ] ;
2022-09-02 20:39:00 -06:00
[ self . appDelegate . feedDetailViewController reloadWithSizing ] ;
2021-12-20 20:40:43 -07:00
} ] ;
2021-05-29 21:25:43 -07:00
[ viewController addThemeSegmentedControl ] ;
UINavigationController * navController = self . navigationController ;
[ viewController showFromNavigationController : navController barButtonItem : self . settingsBarButton permittedArrowDirections : UIPopoverArrowDirectionDown ] ;
}
- ( void ) showLoginAsDialog {
UIAlertController * alertController = [ UIAlertController alertControllerWithTitle : @ "Login as..." message : nil preferredStyle : UIAlertControllerStyleAlert ] ;
[ alertController addTextFieldWithConfigurationHandler : nil ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : @ "Login" style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * action ) {
[ alertController dismissViewControllerAnimated : YES completion : nil ] ;
NSString * username = alertController . textFields [ 0 ] . text ;
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/login_as?user=%@" ,
self . appDelegate . url , username ] ;
[ self . appDelegate GET : urlString parameters : nil success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
NSLog ( @ "Login as %@ successful" , username ) ;
[ MBProgressHUD hideHUDForView : self . appDelegate . feedsViewController . view animated : YES ] ;
[ self . appDelegate reloadFeedsView : YES ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
2022-03-08 21:32:08 -07:00
NSLog ( @ "Login as %@ gave error, but probably worked: %@" , username , error ) ;
2021-05-29 21:25:43 -07:00
[ MBProgressHUD hideHUDForView : self . appDelegate . feedsViewController . view animated : YES ] ;
2022-03-08 21:32:08 -07:00
[ self . appDelegate reloadFeedsView : YES ] ;
2021-05-29 21:25:43 -07:00
} ] ;
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
MBProgressHUD * HUD = [ MBProgressHUD showHUDAddedTo : self . appDelegate . feedsViewController . view animated : YES ] ;
HUD . labelText = [ NSString stringWithFormat : @ "Login: %@" , username ] ;
} ] ] ;
[ alertController addAction : [ UIAlertAction actionWithTitle : @ "Cancel"
style : UIAlertActionStyleCancel handler : nil ] ] ;
[ appDelegate . feedsViewController presentViewController : alertController animated : YES completion : nil ] ;
2011-08-21 21:39:29 -07:00
}
2015-12-15 12:37:18 -08:00
- ( IBAction ) showInteractionsPopover : ( id ) sender {
2016-02-29 18:24:24 -08:00
if ( self . presentedViewController ) {
[ self . presentedViewController dismissViewControllerAnimated : YES completion : nil ] ;
return ;
}
2015-12-15 12:37:18 -08:00
CGSize size = CGSizeMake ( self . view . frame . size . width - 36 ,
self . view . frame . size . height - 60 ) ;
[ self . appDelegate showPopoverWithViewController : self . appDelegate . dashboardViewController contentSize : size barButtonItem : self . activitiesButton ] ;
2013-02-21 16:53:37 -08:00
[ appDelegate . dashboardViewController refreshInteractions ] ;
[ appDelegate . dashboardViewController refreshActivity ] ;
}
2013-10-08 19:33:11 -07:00
- ( void ) handleLongPress : ( UILongPressGestureRecognizer * ) gestureRecognizer {
CGPoint p = [ gestureRecognizer locationInView : self . feedTitlesTable ] ;
NSIndexPath * indexPath = [ self . feedTitlesTable indexPathForRowAtPoint : p ] ;
2013-10-09 15:41:17 -07:00
2013-10-08 19:33:11 -07:00
if ( gestureRecognizer . state ! = UIGestureRecognizerStateBegan ) return ;
if ( indexPath = = nil ) return ;
2013-10-09 15:41:17 -07:00
FeedTableCell * cell = ( FeedTableCell * ) [ self . feedTitlesTable cellForRowAtIndexPath : indexPath ] ;
if ( ! cell . highlighted ) return ;
2014-03-04 18:09:43 -08:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
NSString * longPressTitle = [ preferences stringForKey : @ "long_press_feed_title" ] ;
2013-10-09 15:41:17 -07:00
2013-10-08 19:33:11 -07:00
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
id feedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : indexPath . row ] ;
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2015-11-13 21:54:32 -08:00
// BOOL isSocial = [ appDelegate isSocialFeed : feedIdStr ] ;
2016-03-26 21:27:25 -07:00
BOOL isSaved = [ appDelegate isSavedFeed : feedIdStr ] || self . appDelegate . isSavedStoriesIntelligenceMode ;
2014-05-20 12:58:04 -07:00
if ( isSaved ) return ;
2013-10-10 14:12:04 -07:00
[ self performSelector : @ selector ( highlightCell : ) withObject : cell afterDelay : 0.0 ] ;
2014-03-04 18:09:43 -08:00
if ( [ longPressTitle isEqualToString : @ "mark_read_choose_days" ] ) {
2015-11-13 21:54:32 -08:00
// NSDictionary * feed = isSocial ?
// [ appDelegate . dictSocialFeeds objectForKey : feedIdStr ] :
// [ appDelegate . dictFeeds objectForKey : feedIdStr ] ;
2017-10-04 17:11:53 -07:00
[ self . appDelegate showMarkReadMenuWithFeedIds : @ [ feedIdStr ] collectionTitle : @ "site" sourceView : self . feedTitlesTable sourceRect : cell . frame completionHandler : ^ ( BOOL marked ) {
2015-11-13 21:54:32 -08:00
for ( FeedTableCell * cell in [ self . feedTitlesTable visibleCells ] ) {
if ( cell . highlighted ) {
[ self performSelector : @ selector ( unhighlightCell : ) withObject : cell afterDelay : 0.0 ] ;
break ;
}
}
} ] ;
2014-03-04 18:09:43 -08:00
} else if ( [ longPressTitle isEqualToString : @ "mark_read_immediate" ] ) {
[ self markFeedRead : feedId cutoffDays : 0 ] ;
2022-11-09 19:32:04 -07:00
if ( [ preferences boolForKey : @ "show_feeds_after_being_read" ] ) {
2014-03-04 18:09:43 -08:00
[ self . stillVisibleFeeds setObject : indexPath forKey : feedIdStr ] ;
2022-11-09 19:32:04 -07:00
}
2014-03-04 18:09:43 -08:00
[ self . feedTitlesTable beginUpdates ] ;
[ self . feedTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . feedTitlesTable endUpdates ] ;
}
2013-10-10 14:12:04 -07:00
}
- ( void ) highlightCell : ( FeedTableCell * ) cell {
[ cell setHighlighted : YES ] ;
}
- ( void ) unhighlightCell : ( FeedTableCell * ) cell {
[ cell setHighlighted : NO ] ;
2014-03-04 18:09:43 -08:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
2014-09-22 16:46:07 -07:00
NSLog ( @ "unhighlight cell" ) ;
2014-03-04 18:09:43 -08:00
if ( ! [ preferences boolForKey : @ "show_feeds_after_being_read" ] ) {
NSIndexPath * indexPath = [ self . feedTitlesTable indexPathForCell : cell ] ;
[ self . feedTitlesTable beginUpdates ] ;
[ self . feedTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . feedTitlesTable endUpdates ] ;
}
2013-10-08 19:33:11 -07:00
}
2013-07-11 18:36:09 -07:00
# pragma mark -
# pragma mark Preferences
2015-12-07 16:09:49 -08:00
- ( void ) settingsViewControllerWillAppear : ( IASKAppSettingsViewController * ) sender {
[ [ ThemeManager themeManager ] updatePreferencesTheme ] ;
}
2013-06-21 17:48:06 -07:00
- ( void ) settingsViewControllerDidEnd : ( IASKAppSettingsViewController * ) sender {
2020-08-29 21:19:32 -07:00
[ appDelegate . feedsNavigationController dismissViewControllerAnimated : YES completion : nil ] ;
2014-10-01 14:23:57 -07:00
[ self resizeFontSize ] ;
2016-11-24 16:41:41 -05:00
[ self resetupGestures ] ;
2014-10-01 14:23:57 -07:00
}
2019-02-05 21:05:34 -08:00
- ( void ) resizePreviewSize {
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2019-02-05 21:05:34 -08:00
2022-09-02 20:39:00 -06:00
[ appDelegate . feedDetailViewController reloadWithSizing ] ;
2019-02-05 21:05:34 -08:00
}
2014-10-01 14:23:57 -07:00
- ( void ) resizeFontSize {
appDelegate . fontDescriptorTitleSize = nil ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2014-10-01 14:23:57 -07:00
appDelegate . feedDetailViewController . invalidateFontCache = YES ;
2022-09-02 20:39:00 -06:00
[ appDelegate . feedDetailViewController reloadWithSizing ] ;
2013-06-21 17:48:06 -07:00
}
2015-12-07 16:09:49 -08:00
- ( void ) updateTheme {
[ super updateTheme ] ;
2020-03-29 16:21:00 -07:00
// CATALYST : This prematurely dismisses the login view controller ; is it really appropriate ?
// if ( ! [ self . presentedViewController isKindOfClass : [ UINavigationController class ] ] || ( ( ( UINavigationController * ) self . presentedViewController ) . topViewController ! = ( UIViewController * ) self . appDelegate . fontSettingsViewController && ! [ ( ( UINavigationController * ) self . presentedViewController ) . topViewController conformsToProtocol : @ protocol ( IASKViewController ) ] ) ) {
// [ self . presentedViewController dismissViewControllerAnimated : YES completion : nil ] ;
// }
2015-12-13 21:46:07 -08:00
2015-12-15 12:37:18 -08:00
[ self . appDelegate hidePopoverAnimated : YES ] ;
2015-12-13 21:46:07 -08:00
2021-12-08 20:50:10 -07:00
UINavigationBarAppearance * appearance = [ [ UINavigationBarAppearance alloc ] initWithIdiom : [ [ UIDevice currentDevice ] userInterfaceIdiom ] ] ;
appearance . backgroundColor = [ UINavigationBar appearance ] . barTintColor ;
self . navigationController . navigationBar . scrollEdgeAppearance = appearance ;
self . navigationController . navigationBar . standardAppearance = appearance ;
2016-02-27 13:20:32 -08:00
self . navigationController . navigationBar . tintColor = [ UINavigationBar appearance ] . tintColor ;
self . navigationController . navigationBar . barTintColor = [ UINavigationBar appearance ] . barTintColor ;
2021-03-28 16:03:59 -07:00
self . navigationController . navigationBar . barStyle = ThemeManager . shared . isDarkTheme ? UIBarStyleBlack : UIBarStyleDefault ;
2016-02-27 13:20:32 -08:00
self . navigationController . toolbar . tintColor = [ UIToolbar appearance ] . tintColor ;
self . navigationController . toolbar . barTintColor = [ UIToolbar appearance ] . barTintColor ;
self . feedViewToolbar . tintColor = [ UINavigationBar appearance ] . tintColor ;
self . feedViewToolbar . barTintColor = [ UINavigationBar appearance ] . barTintColor ;
2016-02-23 14:36:32 -08:00
self . addBarButton . tintColor = UIColorFromRGB ( 0 x8F918B ) ;
self . settingsBarButton . tintColor = UIColorFromRGB ( 0 x8F918B ) ;
2016-09-13 15:38:51 -07:00
self . refreshControl . tintColor = UIColorFromLightDarkRGB ( 0 x0 , 0 xffffff ) ;
self . refreshControl . backgroundColor = UIColorFromRGB ( 0 xE3E6E0 ) ;
2017-10-18 21:18:19 -07:00
self . view . backgroundColor = UIColorFromRGB ( 0 xf4f4f4 ) ;
2015-12-07 16:09:49 -08:00
2019-08-24 21:02:21 -07:00
[ [ ThemeManager themeManager ] updateSegmentedControl : self . intelligenceControl ] ;
2016-03-19 21:26:56 -07:00
NBBarButtonItem * barButton = self . addBarButton . customView ;
[ barButton setImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "nav_icn_add.png" ] ] forState : UIControlStateNormal ] ;
2022-08-17 21:48:20 -07:00
self . settingsBarButton . image = [ Utilities imageNamed : @ "settings" sized : 30 ] ;
2016-02-23 14:36:32 -08:00
2016-10-05 21:03:32 -07:00
[ self layoutHeaderCounts : 0 ] ;
2015-12-14 20:44:28 -08:00
[ self refreshHeaderCounts ] ;
2015-12-07 16:09:49 -08:00
2018-08-29 14:55:37 -07:00
self . searchBar . backgroundColor = UIColorFromRGB ( 0 xE3E6E0 ) ;
self . searchBar . tintColor = UIColorFromRGB ( 0 xffffff ) ;
self . searchBar . nb_searchField . textColor = UIColorFromRGB ( NEWSBLUR_BLACK _COLOR ) ;
self . searchBar . nb_searchField . tintColor = UIColorFromRGB ( NEWSBLUR_BLACK _COLOR ) ;
if ( [ ThemeManager themeManager ] . isDarkTheme ) {
2020-07-21 20:30:02 -07:00
self . feedTitlesTable . indicatorStyle = UIScrollViewIndicatorStyleWhite ;
2018-08-29 14:55:37 -07:00
self . searchBar . keyboardAppearance = UIKeyboardAppearanceDark ;
} else {
2020-07-21 20:30:02 -07:00
self . feedTitlesTable . indicatorStyle = UIScrollViewIndicatorStyleBlack ;
2018-08-29 14:55:37 -07:00
self . searchBar . keyboardAppearance = UIKeyboardAppearanceDefault ;
}
2017-11-15 10:47:57 -08:00
self . feedTitlesTable . backgroundColor = UIColorFromRGB ( 0 xf4f4f4 ) ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2017-04-13 12:46:39 -07:00
[ self resetupGestures ] ;
2015-12-07 16:09:49 -08:00
}
- ( void ) updateThemeBrightness {
if ( [ [ ThemeManager themeManager ] autoChangeTheme ] ) {
[ [ ThemeManager themeManager ] updateTheme ] ;
}
}
- ( void ) updateThemeStyle {
[ [ ThemeManager themeManager ] updateTheme ] ;
}
2022-04-22 19:23:40 -07:00
- ( void ) settingsUpdateSpecifierDictionary : ( NSMutableDictionary * ) dictionary {
NSMutableArray * titles = dictionary [ @ "Titles" ] ;
NSMutableArray * values = dictionary [ @ "Values" ] ;
[ titles removeAllObjects ] ;
[ values removeAllObjects ] ;
[ titles addObject : @ "Show feed list" ] ;
2022-07-08 21:29:43 -07:00
[ titles addObject : @ "Open All Site Stories" ] ;
2022-04-22 19:23:40 -07:00
[ values addObject : @ "feeds" ] ;
[ values addObject : @ "everything" ] ;
for ( NSString * folder in self . appDelegate . dictFoldersArray ) {
if ( [ folder hasPrefix : @ "river_" ] || [ folder isEqualToString : @ "everything" ] || [ folder isEqualToString : @ "infrequent" ] || [ folder isEqualToString : @ "widget" ] || [ folder isEqualToString : @ "read_stories" ] || [ folder hasPrefix : @ "saved_" ] ) {
continue ;
}
[ titles addObject : [ NSString stringWithFormat : @ "Open %@" , folder ] ] ;
[ values addObject : folder ] ;
}
}
2013-06-21 17:48:06 -07:00
- ( void ) settingDidChange : ( NSNotification * ) notification {
2015-12-07 16:09:49 -08:00
NSString * identifier = notification . object ;
2019-08-24 19:09:44 -07:00
if ( ! [ identifier isKindOfClass : [ NSString class ] ] ) {
identifier = notification . userInfo . allKeys . firstObject ;
}
2021-06-10 19:50:56 -07:00
if ( [ identifier isEqualToString : @ "split_behavior" ] ) {
2023-06-26 21:51:36 -07:00
[ self . appDelegate updateSplitBehavior : YES ] ;
2021-06-10 19:50:56 -07:00
} else if ( [ identifier isEqualToString : @ "feed_list_sort_order" ] ) {
2019-08-24 19:09:44 -07:00
[ self . appDelegate reloadFeedsView : YES ] ;
2015-12-07 16:09:49 -08:00
} else if ( [ identifier isEqual : @ "feed_list_font_size" ] ) {
2014-10-01 14:23:57 -07:00
[ self resizeFontSize ] ;
2015-12-07 16:09:49 -08:00
} else if ( [ identifier isEqual : @ "theme_auto_brightness" ] ) {
[ self updateThemeBrightness ] ;
} else if ( [ identifier isEqual : @ "theme_style" ] ) {
[ self updateThemeStyle ] ;
2023-07-20 21:07:56 -06:00
} else if ( [ identifier isEqual : self . appDelegate . storiesCollection . storyTitlesPositionKey ] ) {
2023-07-21 21:15:24 -06:00
[ self . appDelegate . detailViewController updateLayoutWithReload : YES fetchFeeds : YES ] ;
2023-05-25 21:47:34 -07:00
} else if ( [ identifier isEqual : @ "story_titles_style" ] ) {
2023-07-21 21:15:24 -06:00
[ self . appDelegate . detailViewController updateLayoutWithReload : YES fetchFeeds : YES ] ;
2018-11-12 20:27:46 -08:00
} else if ( [ identifier isEqual : @ "story_list_preview_images_size" ] ) {
2022-01-26 21:37:41 -08:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
NSString * preview = [ userPreferences stringForKey : @ "story_list_preview_images_size" ] ;
NSUserDefaults * defaults = [ [ NSUserDefaults alloc ] initWithSuiteName : @ "group.com.newsblur.NewsBlur-Group" ] ;
[ defaults setObject : preview forKey : @ "widget:preview_images_size" ] ;
[ self . appDelegate . storyPagesViewController reloadWidget ] ;
2013-11-23 13:14:30 -08:00
}
2019-09-21 14:51:55 -07:00
[ appDelegate setHiddenPreferencesAnimated : YES ] ;
2013-07-11 18:36:09 -07:00
}
- ( void ) settingsViewController : ( IASKAppSettingsViewController * ) sender buttonTappedForSpecifier : ( IASKSpecifier * ) specifier {
if ( [ specifier . key isEqualToString : @ "offline_cache_empty_stories" ] ) {
dispatch_queue _t queue = dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _HIGH , 0 ul ) ;
dispatch_async ( queue , ^ {
2013-10-08 16:00:55 -07:00
dispatch_sync ( dispatch_get _main _queue ( ) , ^ {
[ [ NSUserDefaults standardUserDefaults ] setObject : @ "Deleting..." forKey : specifier . key ] ;
} ) ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate . database inDatabase : ^ ( FMDatabase * db ) {
2017-04-04 15:33:08 -07:00
[ db executeUpdate : @ "VACUUM" ] ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate setupDatabase : db force : YES ] ;
2019-11-25 14:27:59 -08:00
[ db executeUpdate : @ "DELETE FROM stories" ] ;
[ db executeUpdate : @ "DELETE FROM text" ] ;
[ db executeUpdate : @ "DELETE FROM cached_images" ] ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate deleteAllCachedImages ] ;
2017-04-04 15:33:08 -07:00
dispatch_sync ( dispatch_get _main _queue ( ) , ^ {
[ [ NSUserDefaults standardUserDefaults ] setObject : @ "Cleared all stories and images!"
forKey : specifier . key ] ;
} ) ;
2013-07-11 18:36:09 -07:00
} ] ;
} ) ;
2020-01-27 20:27:44 -08:00
} else if ( [ specifier . key isEqualToString : @ "import_prefs" ] ) {
[ ImportExportPreferences importFromController : sender ] ;
} else if ( [ specifier . key isEqualToString : @ "export_prefs" ] ) {
[ ImportExportPreferences exportFromController : sender ] ;
2022-03-09 21:06:09 -07:00
} else if ( [ specifier . key isEqualToString : @ "delete_account" ] ) {
[ sender dismiss : nil ] ;
NSString * urlString = [ NSString stringWithFormat : @ "%@/profile/delete_account" ,
self . appDelegate . url ] ;
[ self . appDelegate showInAppBrowser : [ NSURL URLWithString : urlString ] withCustomTitle : @ "Delete Account" fromSender : nil ] ;
2020-01-27 20:27:44 -08:00
}
2013-06-21 17:48:06 -07:00
}
2019-12-20 19:09:20 -08:00
- ( void ) validateWidgetFeedsForGroupDefaults : ( NSUserDefaults * ) groupDefaults usingResults : ( NSDictionary * ) results {
2019-12-23 21:19:45 -08:00
NSMutableArray * feeds = [ groupDefaults objectForKey : @ "widget:feeds_array" ] ;
2019-12-20 19:09:20 -08:00
if ( feeds = = nil ) {
2019-12-23 21:19:45 -08:00
feeds = [ NSMutableArray array ] ;
2019-12-20 19:09:20 -08:00
NSDictionary * resultsFeeds = results [ @ "feeds" ] ;
[ resultsFeeds enumerateKeysAndObjectsUsingBlock : ^ ( id key , NSDictionary * obj , BOOL * stop ) {
2020-01-22 17:50:58 -08:00
NSMutableDictionary * feed = [ NSMutableDictionary dictionary ] ;
2019-12-23 21:19:45 -08:00
NSString * fade = obj [ @ "favicon_fade" ] ;
NSString * color = obj [ @ "favicon_color" ] ;
2019-12-20 19:09:20 -08:00
2020-01-22 17:50:58 -08:00
feed [ @ "id" ] = [ NSString stringWithFormat : @ "%@" , key ] ;
feed [ @ "feed_title" ] = [ NSString stringWithFormat : @ "%@" , obj [ @ "feed_title" ] ] ;
if ( fade ! = nil && ! [ fade isKindOfClass : [ NSNull class ] ] ) {
feed [ @ "favicon_fade" ] = fade ;
}
if ( color ! = nil && ! [ color isKindOfClass : [ NSNull class ] ] ) {
feed [ @ "favicon_color" ] = color ;
}
2019-12-23 21:19:45 -08:00
[ feeds addObject : feed ] ;
2019-12-20 19:09:20 -08:00
} ] ;
2019-12-23 21:19:45 -08:00
[ groupDefaults setObject : feeds forKey : @ "widget:feeds_array" ] ;
2019-12-20 19:09:20 -08:00
}
}
2010-06-20 11:04:23 -04:00
# pragma mark -
# pragma mark Table View - Feed List
- ( NSInteger ) numberOfSectionsInTableView : ( UITableView * ) tableView {
2012-10-02 15:39:18 -07:00
if ( appDelegate . hasNoSites ) {
2013-09-05 16:34:39 -07:00
return 0 ;
2012-08-02 19:43:55 -07:00
}
2011-10-04 18:01:35 -07:00
return [ appDelegate . dictFoldersArray count ] ;
2010-06-20 11:04:23 -04:00
}
- ( NSString * ) tableView : ( UITableView * ) tableView titleForHeaderInSection : ( NSInteger ) section {
2011-10-04 18:01:35 -07:00
return [ appDelegate . dictFoldersArray objectAtIndex : section ] ;
2010-06-20 11:04:23 -04:00
}
- ( NSInteger ) tableView : ( UITableView * ) tableView numberOfRowsInSection : ( NSInteger ) section {
2012-10-02 15:39:18 -07:00
if ( appDelegate . hasNoSites ) {
2012-08-02 19:43:55 -07:00
return 1 ;
}
2011-10-04 18:01:35 -07:00
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : section ] ;
2014-05-20 12:21:17 -07:00
2022-11-28 10:03:40 -06:00
NSInteger count = [ [ appDelegate . dictFolders objectForKey : folderName ] count ] ;
NSInteger limit = 5000 ;
if ( count > limit ) {
NSLog ( @ "Folder %@ contains %@ feeds; limiting to %@" , folderName , @ ( count ) , @ ( limit ) ) ; // log
count = limit ;
}
2023-01-04 21:29:06 -06:00
// NSLog ( @ "Folder %@ contains %@ feeds" , folderName , @ ( count ) ) ; // log
2022-11-28 10:03:40 -06:00
return count ;
2010-06-20 11:04:23 -04:00
}
2011-08-02 18:03:11 -07:00
- ( UITableViewCell * ) tableView : ( UITableView * ) tableView
2011-11-29 18:39:52 -08:00
cellForRowAtIndexPath : ( NSIndexPath * ) indexPath {
2012-12-20 12:08:35 -08:00
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
2023-01-04 21:29:06 -06:00
NSArray * folder = [ appDelegate . dictFolders objectForKey : folderName ] ;
if ( indexPath . row >= folder . count ) {
NSLog ( @ "Detected attempt to access row %@ of %@ when there are only %@; this will crash!" , @ ( indexPath . row ) , folderName , @ ( folder . count ) ) ; // log
}
id feedId = [ folder objectAtIndex : indexPath . row ] ;
2012-12-20 12:08:35 -08:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2020-09-22 20:52:10 -07:00
BOOL isSavedSearch = [ appDelegate isSavedSearch : feedIdStr ] ;
2020-06-11 21:02:22 -07:00
NSString * searchQuery = [ appDelegate searchQueryForFeedId : feedIdStr ] ;
NSString * searchFolder = [ appDelegate searchFolderForFeedId : feedIdStr ] ;
feedIdStr = [ appDelegate feedIdWithoutSearchQuery : feedIdStr ] ;
2012-12-20 12:08:35 -08:00
BOOL isSocial = [ appDelegate isSocialFeed : feedIdStr ] ;
2014-05-20 12:21:17 -07:00
BOOL isSaved = [ appDelegate isSavedFeed : feedIdStr ] ;
2016-03-26 21:27:25 -07:00
BOOL isSavedStoriesFeed = self . appDelegate . isSavedStoriesIntelligenceMode && [ self . appDelegate savedStoriesCountForFeed : feedIdStr ] > 0 ;
2020-06-15 19:57:06 -07:00
BOOL isInactive = appDelegate . dictInactiveFeeds [ feedIdStr ] ! = nil ;
2018-08-29 14:55:37 -07:00
BOOL isOmitted = false ;
2013-10-18 14:17:01 -07:00
NSString * CellIdentifier ;
2018-08-29 14:55:37 -07:00
if ( self . searchFeedIds && ! isSaved ) {
isOmitted = ! [ self . searchFeedIds containsObject : feedIdStr ] ;
} else {
2020-09-22 20:52:10 -07:00
isOmitted = [ appDelegate isFolderCollapsed : folderName ] || ! ( [ self isFeedVisible : feedIdStr ] || isSavedSearch ) ;
2018-08-29 14:55:37 -07:00
}
if ( isOmitted ) {
2013-10-18 14:17:01 -07:00
CellIdentifier = @ "BlankCellIdentifier" ;
UITableViewCell * cell = [ tableView dequeueReusableCellWithIdentifier : CellIdentifier ] ;
if ( ! cell ) {
cell = [ [ UITableViewCell alloc ] initWithStyle : UITableViewCellStyleDefault reuseIdentifier : CellIdentifier ] ;
}
return cell ;
} else if ( indexPath . section = = 0 || indexPath . section = = 1 ) {
2012-07-18 21:41:38 -07:00
CellIdentifier = @ "BlurblogCellIdentifier" ;
2014-05-20 12:21:17 -07:00
} else if ( isSaved ) {
CellIdentifier = @ "SavedCellIdentifier" ;
2012-07-18 21:41:38 -07:00
} else {
CellIdentifier = @ "FeedCellIdentifier" ;
}
2012-12-20 12:08:35 -08:00
2016-01-27 21:50:44 -08:00
FeedTableCell * cell = ( FeedTableCell * ) [ tableView dequeueReusableCellWithIdentifier : CellIdentifier ] ;
2016-11-27 16:30:57 -05:00
BOOL newCell = cell = = nil ;
if ( newCell ) {
2012-11-19 19:15:05 -08:00
cell = [ [ FeedTableCell alloc ]
initWithStyle : UITableViewCellStyleDefault
reuseIdentifier : CellIdentifier ] ;
2013-07-26 17:58:58 -07:00
cell . appDelegate = appDelegate ;
2011-08-24 21:44:16 -07:00
}
2012-12-20 12:08:35 -08:00
NSDictionary * feed = isSocial ?
[ appDelegate . dictSocialFeeds objectForKey : feedIdStr ] :
2014-05-20 12:21:17 -07:00
isSaved ?
[ appDelegate . dictSavedStoryTags objectForKey : feedIdStr ] :
2012-12-20 12:08:35 -08:00
[ appDelegate . dictFeeds objectForKey : feedIdStr ] ;
2013-06-29 17:28:41 -07:00
NSDictionary * unreadCounts = [ appDelegate . dictUnreadCounts objectForKey : feedIdStr ] ;
2014-05-20 13:12:03 -07:00
cell . feedFavicon = [ appDelegate getFavicon : feedIdStr isSocial : isSocial isSaved : isSaved ] ;
2011-10-17 09:37:16 -07:00
cell . feedTitle = [ feed objectForKey : @ "feed_title" ] ;
2012-06-27 10:18:29 -07:00
cell . isSocial = isSocial ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
cell . isSearch = isSavedSearch ;
2014-05-20 12:58:04 -07:00
cell . isSaved = isSaved ;
2020-06-15 19:57:06 -07:00
cell . isInactive = isInactive ;
2020-06-11 21:02:22 -07:00
cell . searchQuery = searchQuery ;
2011-08-24 21:44:16 -07:00
2021-05-08 14:00:46 -07:00
NSArray * folderComponents = [ folderName componentsSeparatedByString : @ " ▸ " ] ;
2022-03-09 19:16:43 -07:00
BOOL isTopLevel = [ folderName isEqualToString : @ "everything" ] || [ folderName isEqualToString : @ "widget_stories" ] || [ folderName isEqualToString : @ "saved_searches" ] || [ folderName isEqualToString : @ "saved_stories" ] ;
2021-05-08 14:00:46 -07:00
2021-05-20 16:10:25 -07:00
cell . indentationLevel = isTopLevel ? 0 : folderComponents . count ;
2021-05-08 14:00:46 -07:00
cell . indentationWidth = 28 ;
2016-11-27 16:30:57 -05:00
if ( newCell ) {
[ cell setupGestures ] ;
}
2020-06-11 21:02:22 -07:00
if ( searchQuery ! = nil ) {
2020-05-27 21:26:44 -07:00
cell . positiveCount = 0 ;
cell . neutralCount = 0 ;
cell . negativeCount = 0 ;
cell . savedStoriesCount = 0 ;
cell . feedTitle = [ NSString stringWithFormat : @ "\" % @ \ " in %@" , cell . searchQuery , cell . feedTitle ] ;
2020-06-11 21:02:22 -07:00
if ( searchFolder ! = nil ) {
cell . feedFavicon = [ appDelegate folderIcon : searchFolder ] ;
cell . feedTitle = [ NSString stringWithFormat : @ "\" % @ \ " in %@" , cell . searchQuery , [ appDelegate folderTitle : searchFolder ] ] ;
}
2020-06-15 19:57:06 -07:00
} else if ( isInactive ) {
cell . positiveCount = 0 ;
cell . neutralCount = 0 ;
cell . negativeCount = 0 ;
cell . savedStoriesCount = 0 ;
2020-05-27 21:26:44 -07:00
} else if ( isSavedStoriesFeed ) {
2016-03-26 21:27:25 -07:00
cell . positiveCount = 0 ;
cell . neutralCount = 0 ;
cell . negativeCount = 0 ;
cell . savedStoriesCount = ( int ) [ self . appDelegate savedStoriesCountForFeed : feedIdStr ] ;
} else {
cell . positiveCount = [ [ unreadCounts objectForKey : @ "ps" ] intValue ] ;
cell . neutralCount = [ [ unreadCounts objectForKey : @ "nt" ] intValue ] ;
cell . negativeCount = [ [ unreadCounts objectForKey : @ "ng" ] intValue ] ;
cell . savedStoriesCount = 0 ;
}
2015-11-04 20:06:46 -08:00
if ( cell . neutralCount ) {
cell . accessibilityLabel = [ NSString stringWithFormat : @ "%@ feed, %@ unread stories" , cell . feedTitle , @ ( cell . neutralCount ) ] ;
} else {
cell . accessibilityLabel = [ NSString stringWithFormat : @ "%@ feed" , cell . feedTitle ] ;
}
2013-10-01 19:32:40 -07:00
[ cell setNeedsDisplay ] ;
2011-08-24 21:44:16 -07:00
return cell ;
2010-06-20 11:04:23 -04:00
}
2011-08-12 10:12:30 -07:00
- ( void ) tableView : ( UITableView * ) tableView
2011-11-29 18:39:52 -08:00
didSelectRowAtIndexPath : ( NSIndexPath * ) indexPath {
2012-07-27 19:42:19 -07:00
2012-10-02 15:39:18 -07:00
if ( appDelegate . hasNoSites ) {
2012-08-02 19:43:55 -07:00
return ;
}
2014-12-02 18:36:38 -08:00
2014-02-25 12:41:20 -08:00
[ appDelegate . storiesCollection reset ] ;
2012-08-02 19:43:55 -07:00
2021-05-21 20:57:06 -07:00
[ self clearSelectedHeader ] ;
2020-08-29 21:19:32 -07:00
if ( self . currentRowAtIndexPath ! = nil && self . currentRowAtIndexPath ! = indexPath ) {
[ self fadeCellWithIndexPath : self . currentRowAtIndexPath ] ;
}
2012-07-27 19:42:19 -07:00
// set the current row pointer
self . currentRowAtIndexPath = indexPath ;
2021-05-21 20:57:06 -07:00
self . currentSection = -1 ;
2022-09-24 21:36:40 -06:00
self . lastRowAtIndexPath = indexPath ;
self . lastSection = -1 ;
2012-07-27 19:42:19 -07:00
2018-01-28 11:08:38 -05:00
NSString * folderName = appDelegate . dictFoldersArray [ indexPath . section ] ;
2012-12-20 12:08:35 -08:00
id feedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : indexPath . row ] ;
2011-08-24 21:44:16 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
2020-06-11 21:02:22 -07:00
NSString * searchQuery = [ appDelegate searchQueryForFeedId : feedIdStr ] ;
NSString * searchFolder = [ appDelegate searchFolderForFeedId : feedIdStr ] ;
feedIdStr = [ appDelegate feedIdWithoutSearchQuery : feedIdStr ] ;
2018-08-29 14:55:37 -07:00
2011-08-24 21:44:16 -07:00
// If all feeds are already showing , no need to remember this one .
2022-11-09 19:32:04 -07:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
if ( ! self . viewShowingAllFeeds && [ preferences boolForKey : @ "show_feeds_after_being_read" ] ) {
2011-08-24 21:44:16 -07:00
[ self . stillVisibleFeeds setObject : indexPath forKey : feedIdStr ] ;
}
2019-09-27 15:46:21 -07:00
[ [ tableView cellForRowAtIndexPath : indexPath ] setNeedsDisplay ] ;
2020-06-11 21:02:22 -07:00
if ( searchFolder ! = nil ) {
[ appDelegate loadRiverFeedDetailView : appDelegate . feedDetailViewController withFolder : searchFolder ] ;
} else {
[ appDelegate loadFolder : folderName feedID : feedIdStr ] ;
}
if ( searchQuery ! = nil ) {
appDelegate . storiesCollection . inSearch = YES ;
appDelegate . storiesCollection . searchQuery = searchQuery ;
appDelegate . storiesCollection . savedSearchQuery = searchQuery ;
}
2010-06-20 11:04:23 -04:00
}
2012-12-10 18:34:13 -08:00
- ( CGFloat ) tableView : ( UITableView * ) tableView
2011-11-29 18:39:52 -08:00
heightForRowAtIndexPath : ( NSIndexPath * ) indexPath {
2019-05-31 20:32:08 -07:00
NSNumber * cachedHeight = self . rowHeights [ indexPath ] ;
if ( cachedHeight ! = nil ) {
// NSLog ( @ "Got cached height: %@" , cachedHeight ) ; // log
return cachedHeight . floatValue ;
}
CGFloat height = [ self calculateHeightForRowAtIndexPath : indexPath ] ;
self . rowHeights [ indexPath ] = @ ( height ) ;
// NSLog ( @ "Calculated height: %@" , @ ( height ) ) ; // log
return height ;
}
- ( CGFloat ) calculateHeightForRowAtIndexPath : ( NSIndexPath * ) indexPath {
2012-10-02 15:39:18 -07:00
if ( appDelegate . hasNoSites ) {
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
2012-08-02 19:43:55 -07:00
return kBlurblogTableViewRowHeight ;
} else {
return kPhoneBlurblogTableViewRowHeight ;
}
}
2018-01-28 11:08:38 -05:00
NSString * folderName = appDelegate . dictFoldersArray [ indexPath . section ] ;
2012-12-20 12:08:35 -08:00
id feedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : indexPath . row ] ;
2018-08-29 14:55:37 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
if ( self . searchFeedIds && ! [ appDelegate isSavedFeed : feedIdStr ] ) {
if ( ! [ self . searchFeedIds containsObject : feedIdStr ] ) {
return 0 ;
}
} else {
BOOL isFolderCollapsed = [ appDelegate isFolderCollapsed : folderName ] ;
if ( isFolderCollapsed ) {
return 0 ;
}
2022-08-02 21:46:26 -07:00
for ( NSString * parentName in [ self parentTitlesForFolderTitle : folderName ] ) {
if ( [ appDelegate isFolderCollapsed : parentName ] ) {
return 0 ;
}
}
2018-08-29 14:55:37 -07:00
if ( ! [ self isFeedVisible : feedId ] ) {
return 0 ;
}
2012-12-20 12:08:35 -08:00
}
2022-08-02 21:46:26 -07:00
NSArray * subfolderFeeds = appDelegate . dictSubfolders [ folderName ] ;
for ( id subFeedId in subfolderFeeds ) {
if ( [ subFeedId isEqual : feedId ] ) {
return 0 ;
}
}
2017-10-04 16:34:30 -07:00
NSInteger height ;
2012-12-07 15:17:22 -08:00
if ( [ folderName isEqualToString : @ "river_blurblogs" ] ||
[ folderName isEqualToString : @ "river_global" ] ) { // blurblogs
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
2017-10-04 16:34:30 -07:00
height = kBlurblogTableViewRowHeight ;
2012-08-02 12:01:42 -07:00
} else {
2017-10-04 16:34:30 -07:00
height = kPhoneBlurblogTableViewRowHeight ;
2012-08-02 12:01:42 -07:00
}
2012-07-11 11:03:34 -07:00
} else {
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
2017-10-04 16:34:30 -07:00
height = kTableViewRowHeight ;
2012-08-02 12:01:42 -07:00
} else {
2017-10-04 16:34:30 -07:00
height = kPhoneTableViewRowHeight ;
}
}
UIFontDescriptor * fontDescriptor = [ self fontDescriptorUsingPreferredSize : UIFontTextStyleCaption1 ] ;
2021-03-26 21:51:02 -07:00
UIFont * font = [ UIFont fontWithName : @ "WhitneySSm-Medium" size : fontDescriptor . pointSize ] ;
2021-12-20 20:40:43 -07:00
NSString * spacing = [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "feed_list_spacing" ] ;
NSInteger offset = [ spacing isEqualToString : @ "compact" ] ? 6 : 0 ;
return height + ( font . pointSize * 2 ) - offset ;
2017-10-04 16:34:30 -07:00
}
2019-05-31 20:32:08 -07:00
- ( void ) resetRowHeights {
[ self . rowHeights removeAllObjects ] ;
}
- ( void ) reloadFeedTitlesTable {
[ self resetRowHeights ] ;
[ self . feedTitlesTable reloadData ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ self highlightSelection ] ;
2019-05-31 20:32:08 -07:00
}
2021-06-10 20:33:59 -07:00
- ( void ) updateFeedTitlesTable {
[ self . feedTitlesTable reloadData ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ self highlightSelection ] ;
2021-06-10 20:33:59 -07:00
}
2017-10-04 16:34:30 -07:00
- ( UIFontDescriptor * ) fontDescriptorUsingPreferredSize : ( NSString * ) textStyle {
UIFontDescriptor * fontDescriptor = appDelegate . fontDescriptorTitleSize ;
if ( fontDescriptor ) return fontDescriptor ;
fontDescriptor = [ UIFontDescriptor preferredFontDescriptorWithTextStyle : textStyle ] ;
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
if ( ! [ userPreferences boolForKey : @ "use_system_font_size" ] ) {
if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "xs" ] ) {
2021-04-07 23:12:47 -04:00
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 10.0 f ] ;
2021-03-26 21:51:02 -07:00
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "small" ] ) {
2021-04-07 23:12:47 -04:00
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 12.0 f ] ;
2017-10-04 16:34:30 -07:00
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "medium" ] ) {
2021-04-07 23:12:47 -04:00
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 13.0 f ] ;
2017-10-04 16:34:30 -07:00
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "large" ] ) {
2021-04-07 23:12:47 -04:00
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 16.0 f ] ;
2021-03-26 21:51:02 -07:00
} else if ( [ [ userPreferences stringForKey : @ "feed_list_font_size" ] isEqualToString : @ "xl" ] ) {
2021-04-07 23:12:47 -04:00
fontDescriptor = [ fontDescriptor fontDescriptorWithSize : 18.0 f ] ;
2012-08-02 12:01:42 -07:00
}
2012-07-11 11:03:34 -07:00
}
2017-10-04 16:34:30 -07:00
return fontDescriptor ;
2011-07-19 09:38:49 -07:00
}
2011-08-12 10:12:30 -07:00
- ( UIView * ) tableView : ( UITableView * ) tableView
2011-11-29 18:39:52 -08:00
viewForHeaderInSection : ( NSInteger ) section {
2017-10-04 16:34:30 -07:00
UIFontDescriptor * fontDescriptor = [ self fontDescriptorUsingPreferredSize : UIFontTextStyleCaption1 ] ;
2021-03-26 21:51:02 -07:00
UIFont * font = [ UIFont fontWithName : @ "WhitneySSm-Medium" size : fontDescriptor . pointSize ] ;
2017-10-04 16:34:30 -07:00
NSInteger height = kFolderTitleHeight ;
CGRect rect = CGRectMake ( 0.0 , 0.0 , tableView . frame . size . width , height + font . pointSize * 2 ) ;
2012-10-04 15:44:25 -07:00
FolderTitleView * folderTitle = [ [ FolderTitleView alloc ] initWithFrame : rect ] ;
2014-03-21 16:23:51 -07:00
folderTitle . section = ( int ) section ;
2011-10-26 23:12:21 -07:00
2021-05-21 20:57:06 -07:00
self . folderTitleViews [ @ ( section ) ] = folderTitle ;
2021-05-08 14:00:46 -07:00
2022-01-27 20:53:09 -08:00
if ( self . currentSection = = section ) {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ self highlightSelection ] ;
2022-01-27 20:53:09 -08:00
} ) ;
}
2012-10-02 15:39:18 -07:00
return folderTitle ;
2011-08-12 10:12:30 -07:00
}
2011-10-26 23:12:21 -07:00
- ( IBAction ) sectionTapped : ( UIButton * ) button {
2021-05-21 20:57:06 -07:00
[ self clearSelectedHeader ] ;
2013-02-22 12:13:01 -08:00
button . backgroundColor = UIColorFromRGB ( 0 x214607 ) ;
2011-11-30 18:46:11 -08:00
}
2012-08-08 10:57:38 -07:00
2011-11-30 18:46:11 -08:00
- ( IBAction ) sectionUntapped : ( UIButton * ) button {
2011-10-26 23:12:21 -07:00
}
2012-06-26 12:12:31 -07:00
- ( IBAction ) sectionUntappedOutside : ( UIButton * ) button {
button . backgroundColor = [ UIColor clearColor ] ;
2021-05-21 20:57:06 -07:00
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ self highlightSelection ] ;
2021-05-21 20:57:06 -07:00
}
2022-03-07 19:47:44 -07:00
- ( void ) fadeSelectedHeader {
if ( self . currentSection >= 0 ) {
FolderTitleView * title = self . folderTitleViews [ @ ( self . currentSection ) ] ;
[ UIView animateWithDuration : 0.2 animations : ^ {
title . invisibleHeaderButton . layer . backgroundColor = [ UIColor clearColor ] . CGColor ;
} completion : NULL ] ;
self . currentSection = -1 ;
}
}
2021-05-21 20:57:06 -07:00
- ( void ) clearSelectedHeader {
if ( self . currentSection >= 0 ) {
FolderTitleView * title = self . folderTitleViews [ @ ( self . currentSection ) ] ;
title . invisibleHeaderButton . backgroundColor = UIColor . clearColor ;
2022-01-31 20:21:01 -08:00
self . currentSection = -1 ;
2021-05-21 20:57:06 -07:00
}
}
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
- ( void ) highlightSelection {
if ( self . currentRowAtIndexPath ! = nil ) {
[ self . feedTitlesTable selectRowAtIndexPath : self . currentRowAtIndexPath
animated : NO
scrollPosition : UITableViewScrollPositionNone ] ;
} else if ( self . currentSection >= 0 ) {
2021-05-21 20:57:06 -07:00
FolderTitleView * title = self . folderTitleViews [ @ ( self . currentSection ) ] ;
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
UIColor * color = UIColorFromLightSepiaMediumDarkRGB ( 0 xFFFFD2 , 0 xFFFFD2 , 0 x304050 , 0 x000022 ) ;
CGFloat hue ;
CGFloat saturation ;
CGFloat brightness ;
CGFloat alpha ;
[ color getHue : & hue saturation : & saturation brightness : & brightness alpha : & alpha ] ;
color = [ UIColor colorWithHue : hue saturation : 1 brightness : 1 alpha : alpha ] ;
2021-05-21 20:57:06 -07:00
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
title . invisibleHeaderButton . backgroundColor = color ;
2022-02-15 19:32:15 -08:00
[ title . invisibleHeaderButton setNeedsDisplay ] ;
2021-05-21 20:57:06 -07:00
}
2012-06-26 12:12:31 -07:00
}
2012-12-20 12:21:44 -08:00
- ( CGFloat ) tableView : ( UITableView * ) tableView
heightForHeaderInSection : ( NSInteger ) section {
2017-12-15 16:16:43 -08:00
NSUserDefaults * prefs = [ NSUserDefaults standardUserDefaults ] ;
2013-06-23 22:19:08 -07:00
if ( [ appDelegate . dictFoldersArray count ] = = 0 ) return 0 ;
2012-10-17 15:07:53 -07:00
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : section ] ;
2012-07-20 22:00:30 -07:00
2012-12-20 12:08:35 -08:00
BOOL visibleFeeds = [ [ self . visibleFolders objectForKey : folderName ] boolValue ] ;
2022-07-08 21:29:43 -07:00
if ( ! visibleFeeds && section ! = NewsBlurTopSectionInfrequentSiteStories && section ! = NewsBlurTopSectionAllStories &&
! [ folderName isEqualToString : @ "river_global" ] &&
! [ folderName isEqualToString : @ "river_blurblogs" ] &&
2020-05-27 21:26:44 -07:00
! [ folderName isEqualToString : @ "saved_searches" ] &&
2014-10-22 16:39:37 -07:00
! [ folderName isEqualToString : @ "saved_stories" ] &&
2022-03-09 19:16:43 -07:00
! [ folderName isEqualToString : @ "read_stories" ] &&
! [ folderName isEqualToString : @ "widget_stories" ] ) {
2012-07-20 22:00:30 -07:00
return 0 ;
}
2018-01-28 11:08:38 -05:00
if ( section = = NewsBlurTopSectionInfrequentSiteStories &&
2017-12-15 16:16:43 -08:00
! [ prefs boolForKey : @ "show_infrequent_site_stories" ] ) {
return 0 ;
}
2022-07-08 21:29:43 -07:00
if ( [ folderName isEqual : @ "river_global" ] &&
2017-12-15 16:16:43 -08:00
! [ prefs boolForKey : @ "show_global_shared_stories" ] ) {
return 0 ;
}
2022-08-02 21:46:26 -07:00
for ( NSString * parentName in [ self parentTitlesForFolderTitle : folderName ] ) {
if ( [ appDelegate isFolderCollapsed : parentName ] ) {
return 0 ;
}
}
2017-10-04 16:34:30 -07:00
UIFontDescriptor * fontDescriptor = [ self fontDescriptorUsingPreferredSize : UIFontTextStyleCaption1 ] ;
2021-03-26 21:51:02 -07:00
UIFont * font = [ UIFont fontWithName : @ "WhitneySSm-Medium" size : fontDescriptor . pointSize ] ;
2017-10-04 16:34:30 -07:00
NSInteger height = kFolderTitleHeight ;
return height + font . pointSize * 2 ;
2011-08-12 10:12:30 -07:00
}
2011-10-25 09:47:55 -07:00
- ( void ) didSelectSectionHeader : ( UIButton * ) button {
2015-11-05 16:43:43 -08:00
[ self didSelectSectionHeaderWithTag : button . tag ] ;
}
- ( void ) didSelectSectionHeaderWithTag : ( NSInteger ) tag {
2020-08-29 21:19:32 -07:00
if ( self . currentRowAtIndexPath ! = nil ) {
[ self fadeCellWithIndexPath : self . currentRowAtIndexPath ] ;
2016-02-29 18:35:58 -08:00
}
2021-05-21 20:57:06 -07:00
[ self clearSelectedHeader ] ;
2012-07-27 19:42:19 -07:00
// reset pointer to the cells
self . currentRowAtIndexPath = nil ;
2015-11-05 16:43:43 -08:00
self . currentSection = tag ;
2022-09-24 21:36:40 -06:00
self . lastRowAtIndexPath = nil ;
self . lastSection = tag ;
2015-11-05 16:43:43 -08:00
#1693 (2022 Redesign)
- Laboriously updated the icons (finding the names in the web inspector, updating the code, inspecting the colors, setting those separately, dealing with scaling issues, etc etc).
- Let me know if you spot any icons that I missed, or unscaled icons (they have to be explicitly sized, otherwise appear huge).
- More space between story title and story content.
- More space when reading a folder.
- Added Compact/Comfortable to feed detail menu.
- Changing Compact/Comfortable also adjusts the feed detail list.
- Adjusted the color of the story content etc in the feed detail list.
- Removed top and bottom borders from feed title gradient in story detail.
- More space in story detail header.
- The feed detail is offset when selected.
- Updated the feeds social, search, and saved background colors.
- Unread counts no longer have a shadow, and have more space.
- Folders and feeds remain selected in the feeds list when returning from a story or refreshing.
- Folders in the feeds list no longer have a different background color.
- The folders and feeds highlight is now rounded and unbordered like on web.
2022-07-20 21:35:16 -07:00
[ self highlightSelection ] ;
2021-05-21 20:57:06 -07:00
2022-07-08 21:29:43 -07:00
NSString * folder = [ appDelegate . dictFoldersArray objectAtIndex : tag ] ;
2018-01-28 11:08:38 -05:00
if ( tag >= 0 && tag < [ NewsBlurTopSectionNames count ] ) {
folder = NewsBlurTopSectionNames [ tag ] ;
2022-07-08 21:29:43 -07:00
} else if ( ! [ folder isEqualToString : @ "river_global" ] && ! [ folder isEqualToString : @ "river_blurblogs" ] ) {
2015-11-05 16:43:43 -08:00
folder = [ NSString stringWithFormat : @ "%ld" , ( long ) tag ] ;
2012-12-20 12:21:44 -08:00
}
2012-10-14 17:30:03 -07:00
2015-11-05 16:43:43 -08:00
[ appDelegate loadRiverFeedDetailView : appDelegate . feedDetailViewController withFolder : folder ] ;
2011-10-25 09:28:05 -07:00
}
2022-09-24 21:36:40 -06:00
- ( NSArray * ) allIndexPaths {
NSMutableArray * array = [ NSMutableArray array ] ;
for ( NSInteger section = 0 ; section < self . feedTitlesTable . numberOfSections ; section + + ) {
for ( NSInteger row = 0 ; row < [ self . feedTitlesTable numberOfRowsInSection : section ] ; row + + ) {
[ array addObject : [ NSIndexPath indexPathForRow : row inSection : section ] ] ;
}
}
return array ;
}
- ( void ) selectNextFolderOrFeed {
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , 0.3 * NSEC_PER _SEC ) , dispatch_get _main _queue ( ) , ^ {
if ( self . lastRowAtIndexPath ! = nil ) {
[ self selectNextFeed : nil ] ;
} else {
[ self selectNextFolder : nil ] ;
}
} ) ;
}
- ( void ) selectNextFeed : ( id ) sender {
NSArray * indexPaths = [ self allIndexPaths ] ;
NSIndexPath * indexPath = self . lastRowAtIndexPath ;
2022-11-17 20:30:47 -06:00
NSIndexPath * stopAtIndexPath = indexPath ;
BOOL foundNext ;
2022-09-24 21:36:40 -06:00
2022-11-17 20:30:47 -06:00
do {
foundNext = YES ;
2022-09-24 21:36:40 -06:00
2022-11-17 20:30:47 -06:00
if ( indexPath = = nil ) {
if ( self . lastSection < 0 ) {
indexPath = indexPaths . firstObject ;
} else {
indexPath = [ NSIndexPath indexPathForRow : 0 inSection : self . lastSection ] ;
}
stopAtIndexPath = indexPath ;
} else {
NSInteger index = [ indexPaths indexOfObject : indexPath ] ;
if ( index = = NSNotFound ) {
index = -1 ;
}
index + = 1 ;
if ( index >= indexPaths . count ) {
index = 0 ;
}
indexPath = indexPaths [ index ] ;
2022-09-24 21:36:40 -06:00
}
2022-11-17 20:30:47 -06:00
if ( sender = = nil ) {
2022-11-21 11:17:54 -06:00
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
id feedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : indexPath . row ] ;
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
BOOL isInactive = appDelegate . dictInactiveFeeds [ feedIdStr ] ! = nil ;
2022-11-17 20:30:47 -06:00
2022-11-21 11:17:54 -06:00
if ( isInactive || [ appDelegate isFolderOrParentCollapsed : folderName ] ) {
2022-11-17 20:30:47 -06:00
foundNext = NO ;
2022-11-19 18:40:46 -06:00
} else {
2022-11-21 11:17:54 -06:00
FeedTableCell * cell = ( FeedTableCell * ) [ self tableView : feedTitlesTable cellForRowAtIndexPath : indexPath ] ;
2022-11-19 18:40:46 -06:00
2022-11-21 11:17:54 -06:00
if ( [ cell . reuseIdentifier isEqualToString : @ "BlankCellIdentifier" ] ) {
2022-11-19 18:40:46 -06:00
foundNext = NO ;
2022-11-21 11:17:54 -06:00
} else {
BOOL hasUnread = cell . positiveCount > 0 || cell . neutralCount > 0 || cell . negativeCount > 0 ;
if ( ! hasUnread ) {
foundNext = NO ;
}
2022-11-19 18:40:46 -06:00
}
2022-11-17 20:30:47 -06:00
}
2022-09-24 21:36:40 -06:00
}
2022-11-17 20:30:47 -06:00
} while ( ! foundNext && ! [ indexPath isEqual : stopAtIndexPath ] ) ;
2022-09-24 21:36:40 -06:00
[ self . feedTitlesTable selectRowAtIndexPath : indexPath animated : YES scrollPosition : UITableViewScrollPositionMiddle ] ;
[ self tableView : self . feedTitlesTable didSelectRowAtIndexPath : indexPath ] ;
}
- ( void ) selectPreviousFeed : ( id ) sender {
NSArray * indexPaths = [ self allIndexPaths ] ;
NSIndexPath * indexPath = self . lastRowAtIndexPath ;
if ( indexPath = = nil ) {
if ( self . lastSection < 0 ) {
indexPath = indexPaths . firstObject ;
} else {
indexPath = [ NSIndexPath indexPathForRow : 0 inSection : self . lastSection ] ;
}
}
NSInteger index = [ indexPaths indexOfObject : indexPath ] ;
if ( index = = NSNotFound ) {
index = 0 ;
}
index - = 1 ;
if ( index < 0 ) {
index = indexPaths . count - 1 ;
}
indexPath = indexPaths [ index ] ;
[ self . feedTitlesTable selectRowAtIndexPath : indexPath animated : YES scrollPosition : UITableViewScrollPositionMiddle ] ;
[ self tableView : self . feedTitlesTable didSelectRowAtIndexPath : indexPath ] ;
}
- ( void ) selectNextFolder : ( id ) sender {
NSInteger section = self . lastSection ;
2022-11-17 20:30:47 -06:00
NSInteger stopAtSection = section ;
BOOL foundNext ;
2022-09-24 21:36:40 -06:00
2022-11-17 20:30:47 -06:00
do {
foundNext = YES ;
if ( section < self . feedTitlesTable . numberOfSections - 1 ) {
section + = 1 ;
} else {
section = 0 ;
}
if ( sender = = nil ) {
NSString * folderName = appDelegate . dictFoldersArray [ section ] ;
UnreadCounts * counts = [ appDelegate splitUnreadCountForFolder : folderName ] ;
BOOL hasUnread = counts . ps > 0 || counts . nt > 0 ;
if ( ! hasUnread ) {
foundNext = NO ;
}
}
} while ( ! foundNext && section ! = stopAtSection ) ;
2022-09-24 21:36:40 -06:00
[ self didSelectSectionHeaderWithTag : section ] ;
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : 0 inSection : section ] ;
if ( [ self . feedTitlesTable numberOfRowsInSection : section ] > 0 ) {
[ self . feedTitlesTable scrollToRowAtIndexPath : indexPath atScrollPosition : UITableViewScrollPositionMiddle animated : YES ] ;
}
}
- ( void ) selectPreviousFolder : ( id ) sender {
NSInteger section = self . lastSection ;
if ( section > 0 ) {
section - = 1 ;
} else {
section = self . feedTitlesTable . numberOfSections - 1 ;
}
[ self didSelectSectionHeaderWithTag : section ] ;
NSIndexPath * indexPath = [ NSIndexPath indexPathForRow : 0 inSection : section ] ;
if ( [ self . feedTitlesTable numberOfRowsInSection : section ] > 0 ) {
[ self . feedTitlesTable scrollToRowAtIndexPath : indexPath atScrollPosition : UITableViewScrollPositionMiddle animated : YES ] ;
}
}
2015-11-22 20:09:37 -05:00
- ( void ) selectEverything : ( id ) sender {
2018-01-28 11:08:38 -05:00
[ self didSelectSectionHeaderWithTag : NewsBlurTopSectionAllStories ] ;
2015-11-22 20:09:37 -05:00
}
2013-09-27 17:54:06 -07:00
2022-03-09 20:06:14 -07:00
- ( void ) selectWidgetStories {
2022-03-11 21:30:28 -07:00
NSInteger tag = [ appDelegate . dictFoldersArray indexOfObject : self . appDelegate . widgetFolder ] ;
2022-03-09 20:06:14 -07:00
if ( tag ! = NSNotFound ) {
[ self didSelectSectionHeaderWithTag : tag ] ;
}
}
2013-09-27 17:54:06 -07:00
# pragma mark - MCSwipeTableViewCellDelegate
// When the user starts swiping the cell this method is called
- ( void ) swipeTableViewCellDidStartSwiping : ( MCSwipeTableViewCell * ) cell {
2013-09-30 16:18:11 -07:00
// NSLog ( @ "Did start swiping the cell!" ) ;
2013-09-27 17:54:06 -07:00
}
2013-09-30 16:18:11 -07:00
// When the user is dragging , this method is called and return the dragged percentage from the border
- ( void ) swipeTableViewCell : ( MCSwipeTableViewCell * ) cell didSwipWithPercentage : ( CGFloat ) percentage {
// NSLog ( @ "Did swipe with percentage : %f" , percentage ) ;
}
2013-09-27 17:54:06 -07:00
- ( void ) swipeTableViewCell : ( MCSwipeTableViewCell * ) cell didEndSwipingSwipingWithState : ( MCSwipeTableViewCellState ) state mode : ( MCSwipeTableViewCellMode ) mode {
2016-11-24 16:41:41 -05:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
2013-10-02 16:05:22 -07:00
NSIndexPath * indexPath = [ self . feedTitlesTable indexPathForCell : cell ] ;
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
NSString * feedId = [ NSString stringWithFormat : @ "%@" ,
[ [ appDelegate . dictFolders objectForKey : folderName ]
objectAtIndex : indexPath . row ] ] ;
2020-06-11 21:02:22 -07:00
feedId = [ appDelegate feedIdWithoutSearchQuery : feedId ] ;
2013-10-02 16:05:22 -07:00
if ( state = = MCSwipeTableViewCellState1 ) {
2016-11-24 16:41:41 -05:00
2013-10-02 16:05:22 -07:00
if ( indexPath . section = = 1 ) {
// Profile
NSDictionary * feed = [ appDelegate . dictSocialFeeds objectForKey : feedId ] ;
appDelegate . activeUserProfileId = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "user_id" ] ] ;
appDelegate . activeUserProfileName = [ NSString stringWithFormat : @ "%@" , [ feed objectForKey : @ "username" ] ] ;
[ appDelegate showUserProfileModal : cell ] ;
} else {
2020-01-31 15:50:03 -08:00
NSString * swipe = [ preferences stringForKey : @ "feed_swipe_left" ] ;
if ( [ swipe isEqualToString : @ "notifications" ] ) {
[ appDelegate openNotificationsWithFeed : feedId sender : cell ] ;
} else if ( [ swipe isEqualToString : @ "statistics" ] ) {
[ appDelegate openStatisticsWithFeed : feedId sender : cell ] ;
} else {
// Train
appDelegate . storiesCollection . activeFeed = [ appDelegate . dictFeeds objectForKey : feedId ] ;
[ appDelegate openTrainSiteWithFeedLoaded : NO from : cell ] ;
}
2013-10-02 16:05:22 -07:00
}
2013-09-30 16:18:11 -07:00
} else if ( state = = MCSwipeTableViewCellState3 ) {
// Mark read
2013-10-08 19:33:11 -07:00
[ self markFeedRead : feedId cutoffDays : 0 ] ;
2014-03-04 18:09:43 -08:00
if ( [ preferences boolForKey : @ "show_feeds_after_being_read" ] ) {
[ self . stillVisibleFeeds setObject : indexPath forKey : feedId ] ;
}
2013-09-30 16:18:11 -07:00
[ self . feedTitlesTable beginUpdates ] ;
[ self . feedTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . feedTitlesTable endUpdates ] ;
2017-06-06 12:42:38 -07:00
[ self refreshHeaderCounts ] ;
2013-09-30 16:18:11 -07:00
}
}
2013-10-09 15:41:17 -07:00
# pragma mark -
# pragma mark Mark Feeds as read
2013-09-30 16:18:11 -07:00
2013-10-09 15:41:17 -07:00
- ( void ) markFeedRead : ( NSString * ) feedId cutoffDays : ( NSInteger ) days {
[ self markFeedsRead : @ [ feedId ] cutoffDays : days ] ;
2013-09-27 17:54:06 -07:00
}
2013-10-09 15:41:17 -07:00
- ( void ) markFeedsRead : ( NSArray * ) feedIds cutoffDays : ( NSInteger ) days {
2017-11-05 22:07:43 -08:00
if ( feedIds . count = = 1 && ( [ feedIds . firstObject isEqual : @ "everything" ] || [ feedIds . firstObject isEqual : @ "infrequent" ] ) ) {
2018-01-16 16:51:47 -08:00
[ self markEverythingReadWithDays : days infrequent : [ feedIds . firstObject isEqual : @ "infrequent" ] ] ;
2015-11-18 13:43:04 -08:00
return ;
}
2013-10-08 19:33:11 -07:00
NSTimeInterval cutoffTimestamp = [ [ NSDate date ] timeIntervalSince1970 ] ;
cutoffTimestamp - = ( days * 60 * 60 * 24 ) ;
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_feed_as_read" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2017-03-19 18:15:36 -07:00
NSMutableDictionary * params = [ NSMutableDictionary dictionary ] ;
[ params setObject : feedIds forKey : @ "feed_id" ] ;
2013-10-08 19:33:11 -07:00
if ( days ) {
2017-03-19 12:09:49 -07:00
[ params setObject : [ NSNumber numberWithInteger : cutoffTimestamp ]
2013-10-08 19:33:11 -07:00
forKey : @ "cutoff_timestamp" ] ;
}
2017-12-18 17:04:54 -08:00
2019-08-22 12:03:39 -07:00
[ appDelegate POST : urlString parameters : params success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-04-03 12:49:01 -07:00
[ self finishMarkAllAsRead : params ] ;
2017-03-19 18:15:36 -07:00
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
[ self requestFailedMarkStoryRead : error withParams : params ] ;
} ] ;
2013-10-08 19:33:11 -07:00
if ( ! days ) {
2013-10-09 15:41:17 -07:00
for ( NSString * feedId in feedIds ) {
[ appDelegate markFeedAllRead : feedId ] ;
}
} else {
// [ self showRefreshNotifier ] ;
}
2019-06-26 18:55:46 -07:00
[ self resetRowHeights ] ;
2013-10-09 15:41:17 -07:00
}
2015-11-18 13:43:04 -08:00
- ( void ) markEverythingReadWithDays : ( NSInteger ) days {
2018-01-16 16:51:47 -08:00
[ self markEverythingReadWithDays : days infrequent : NO ] ;
}
- ( void ) markEverythingReadWithDays : ( NSInteger ) days infrequent : ( BOOL ) infrequent {
2015-11-18 13:43:04 -08:00
NSArray * feedIds = [ appDelegate allFeedIds ] ;
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_all_as_read" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2017-03-19 18:15:36 -07:00
NSMutableDictionary * params = [ NSMutableDictionary dictionary ] ;
2017-03-19 12:09:49 -07:00
[ params setObject : [ NSNumber numberWithInteger : days ]
2017-03-19 18:15:36 -07:00
forKey : @ "days" ] ;
2018-01-16 16:51:47 -08:00
if ( infrequent || [ appDelegate . storiesCollection . activeFolder isEqualToString : @ "infrequent" ] ) {
2017-12-18 17:04:54 -08:00
NSUserDefaults * prefs = [ NSUserDefaults standardUserDefaults ] ;
NSString * infrequent = [ NSString stringWithFormat : @ "%ld" , ( long ) [ prefs integerForKey : @ "infrequent_stories_per_month" ] ] ;
[ params setObject : infrequent forKey : @ "infrequent" ] ;
}
2017-03-19 18:15:36 -07:00
2019-08-22 12:03:39 -07:00
[ appDelegate POST : urlString parameters : params success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-04-03 12:49:01 -07:00
[ self finishMarkAllAsRead : params ] ;
2017-03-19 18:15:36 -07:00
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
[ self requestFailedMarkStoryRead : error withParams : params ] ;
} ] ;
2015-11-18 13:43:04 -08:00
if ( ! days ) {
for ( NSString * feedId in feedIds ) {
[ appDelegate markFeedAllRead : feedId ] ;
}
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2015-11-18 13:43:04 -08:00
} else {
2019-06-26 18:55:46 -07:00
[ self resetRowHeights ] ;
2015-11-18 13:43:04 -08:00
// [ self showRefreshNotifier ] ;
}
}
2015-11-13 21:54:32 -08:00
- ( void ) markVisibleStoriesRead {
NSDictionary * feedsStories = [ appDelegate markVisibleStoriesRead ] ;
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/mark_feed_stories_as_read" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2017-04-03 12:49:01 -07:00
NSMutableDictionary * params = [ NSMutableDictionary dictionary ] ;
2017-03-19 12:09:49 -07:00
[ params setObject : [ feedsStories JSONRepresentation ] forKey : @ "feeds_stories" ] ;
2017-04-03 12:49:01 -07:00
2019-08-22 12:03:39 -07:00
[ appDelegate POST : urlString parameters : params success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-04-03 12:49:01 -07:00
[ self finishMarkAllAsRead : params ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
[ self requestFailedMarkStoryRead : error withParams : params ] ;
} ] ;
2015-11-13 21:54:32 -08:00
}
2017-03-19 18:15:36 -07:00
- ( void ) requestFailedMarkStoryRead : ( NSError * ) error withParams : ( NSDictionary * ) params {
[ appDelegate markStoriesRead : [ params objectForKey : @ "stories" ]
inFeeds : [ params objectForKey : @ "feed_id" ]
cutoffTimestamp : [ [ params objectForKey : @ "cutoff_timestamp" ] integerValue ] ] ;
2013-10-09 15:41:17 -07:00
[ self showOfflineNotifier ] ;
2014-02-18 16:44:41 -08:00
self . isOffline = YES ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2013-10-09 15:41:17 -07:00
}
2017-03-19 18:15:36 -07:00
- ( void ) finishMarkAllAsRead : ( NSDictionary * ) params {
2017-04-03 12:49:01 -07:00
// This seems fishy post - ASI rewrite . This needs to know about a cutoff timestamp which it is never given .
2014-02-18 16:44:41 -08:00
self . isOffline = NO ;
2017-03-19 18:15:36 -07:00
if ( [ [ params objectForKey : @ "cutoff_timestamp" ] integerValue ] ) {
2013-10-09 15:41:17 -07:00
id feed ;
2017-03-19 18:15:36 -07:00
if ( [ [ params objectForKey : @ "feed_id" ] count ] = = 1 ) {
feed = [ [ params objectForKey : @ "feed_id" ] objectAtIndex : 0 ] ;
2013-10-09 15:41:17 -07:00
}
[ self refreshFeedList : feed ] ;
2017-03-19 18:15:36 -07:00
} else if ( [ params objectForKey : @ "feed_id" ] ) {
[ appDelegate markFeedReadInCache : [ params objectForKey : @ "feed_id" ] ] ;
2013-10-08 19:33:11 -07:00
}
2022-03-09 19:16:43 -07:00
[ appDelegate . storyPagesViewController reloadWidget ] ;
2013-10-08 19:33:11 -07:00
}
2013-09-30 16:18:11 -07:00
2013-09-27 17:54:06 -07:00
# pragma mark - Table Actions
2012-10-03 15:46:02 -07:00
- ( void ) didCollapseFolder : ( UIButton * ) button {
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2018-01-28 11:08:38 -05:00
NSString * folderName = appDelegate . dictFoldersArray [ button . tag ] ;
2012-10-03 15:46:02 -07:00
NSString * collapseKey = [ NSString stringWithFormat : @ "folderCollapsed:%@" , folderName ] ;
bool isFolderCollapsed = [ userPreferences boolForKey : collapseKey ] ;
if ( isFolderCollapsed ) {
// Expand folder
[ userPreferences setBool : NO forKey : collapseKey ] ;
} else {
// Collapse folder
[ userPreferences setBool : YES forKey : collapseKey ] ;
}
[ userPreferences synchronize ] ;
2014-09-26 18:35:40 -07:00
appDelegate . collapsedFolders = nil ;
2012-10-03 15:46:02 -07:00
2019-05-31 20:32:08 -07:00
[ self resetRowHeights ] ;
2012-12-20 12:08:35 -08:00
[ self . feedTitlesTable beginUpdates ] ;
2012-10-03 15:46:02 -07:00
[ self . feedTitlesTable reloadSections : [ NSIndexSet indexSetWithIndex : button . tag ]
withRowAnimation : UITableViewRowAnimationFade ] ;
[ self . feedTitlesTable endUpdates ] ;
2018-04-06 09:53:00 -04:00
// // Scroll to section header if collapse causes it to scroll far off screen
// NSArray * indexPathsVisibleCells = [ self . feedTitlesTable indexPathsForVisibleRows ] ;
// BOOL firstFeedInFolderVisible = NO ;
// for ( NSIndexPath * indexPath in indexPathsVisibleCells ) {
// if ( indexPath . row = = 0 && indexPath . section = = button . tag ) {
// firstFeedInFolderVisible = YES ;
// }
// }
// if ( ! firstFeedInFolderVisible ) {
// CGRect headerRect = [ self . feedTitlesTable rectForHeaderInSection : button . tag ] ;
// CGPoint headerPoint = CGPointMake ( headerRect . origin . x , headerRect . origin . y ) ;
// // [ self . feedTitlesTable setContentOffset : headerPoint animated : YES ] ;
// }
2012-10-30 17:25:20 -07:00
2012-10-03 15:46:02 -07:00
}
2012-12-20 12:08:35 -08:00
- ( BOOL ) isFeedVisible : ( id ) feedId {
2013-10-18 14:17:01 -07:00
if ( ! [ feedId isKindOfClass : [ NSString class ] ] ) {
feedId = [ NSString stringWithFormat : @ "%@" , feedId ] ;
}
2016-03-26 21:27:25 -07:00
NSDictionary * unreadCounts = self . appDelegate . dictUnreadCounts [ feedId ] ;
NSIndexPath * stillVisible = self . stillVisibleFeeds [ feedId ] ;
if ( ! stillVisible && self . appDelegate . isSavedStoriesIntelligenceMode ) {
2020-09-22 20:52:10 -07:00
return [ self . appDelegate savedStoriesCountForFeed : feedId ] > 0 || [ self . appDelegate isSavedFeed : feedId ] || [ self . appDelegate isSavedSearch : feedId ] ;
} else if ( ! stillVisible && [ self . appDelegate isSavedSearch : feedId ] ) {
return YES ;
2016-03-26 21:27:25 -07:00
} else if ( ! stillVisible &&
2012-12-20 12:08:35 -08:00
appDelegate . selectedIntelligence >= 1 &&
2013-06-29 17:28:41 -07:00
[ [ unreadCounts objectForKey : @ "ps" ] intValue ] <= 0 ) {
2012-12-20 12:08:35 -08:00
return NO ;
} else if ( ! stillVisible &&
! self . viewShowingAllFeeds &&
2013-06-29 17:28:41 -07:00
( [ [ unreadCounts objectForKey : @ "ps" ] intValue ] <= 0 &&
[ [ unreadCounts objectForKey : @ "nt" ] intValue ] <= 0 ) ) {
2012-12-20 12:08:35 -08:00
return NO ;
2020-06-15 19:57:06 -07:00
} else if ( ! stillVisible &&
! self . viewShowingAllFeeds &&
appDelegate . dictInactiveFeeds [ feedId ] ! = nil ) {
return NO ;
2012-12-20 12:08:35 -08:00
}
return YES ;
}
2012-08-12 16:50:34 -07:00
- ( void ) changeToAllMode {
[ self . intelligenceControl setSelectedSegmentIndex : 0 ] ;
2012-12-20 12:08:35 -08:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2012-08-12 16:50:34 -07:00
[ userPreferences setInteger : -1 forKey : @ "selectedIntelligence" ] ;
[ userPreferences synchronize ] ;
}
2015-11-22 20:09:37 -05:00
- ( void ) selectPreviousIntelligence : ( id ) sender {
NSInteger selectedSegmentIndex = intelligenceControl . selectedSegmentIndex ;
if ( selectedSegmentIndex <= 0 )
return ;
[ intelligenceControl setSelectedSegmentIndex : selectedSegmentIndex - 1 ] ;
[ self selectIntelligence ] ;
}
- ( void ) selectNextIntelligence : ( id ) sender {
NSInteger selectedSegmentIndex = intelligenceControl . selectedSegmentIndex ;
2016-03-26 21:27:25 -07:00
if ( selectedSegmentIndex >= intelligenceControl . numberOfSegments - 1 )
2015-11-22 20:09:37 -05:00
return ;
[ intelligenceControl setSelectedSegmentIndex : selectedSegmentIndex + 1 ] ;
[ self selectIntelligence ] ;
}
2011-08-02 09:16:54 -07:00
- ( IBAction ) selectIntelligence {
2012-07-10 12:34:58 -07:00
[ MBProgressHUD hideHUDForView : self . feedTitlesTable animated : NO ] ;
2017-09-27 12:19:58 -07:00
MBProgressHUD * hud = [ MBProgressHUD showHUDAddedTo : self . view animated : YES ] ;
2012-07-09 18:17:01 -07:00
hud . mode = MBProgressHUDModeText ;
hud . removeFromSuperViewOnHide = YES ;
2013-02-06 18:42:15 -08:00
NSIndexPath * topRow ;
if ( [ [ self . feedTitlesTable indexPathsForVisibleRows ] count ] ) {
topRow = [ [ self . feedTitlesTable indexPathsForVisibleRows ] objectAtIndex : 0 ] ;
}
2013-09-24 17:18:20 -07:00
NSInteger selectedSegmentIndex = [ self . intelligenceControl selectedSegmentIndex ] ;
2012-12-20 12:08:35 -08:00
self . stillVisibleFeeds = [ NSMutableDictionary dictionary ] ;
2011-08-27 15:53:51 -07:00
2012-10-03 15:46:02 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2012-12-20 12:08:35 -08:00
int direction ;
2012-07-09 17:32:22 -07:00
if ( selectedSegmentIndex = = 0 ) {
2022-07-08 21:29:43 -07:00
hud . labelText = @ "All Site Stories" ;
2012-07-16 19:45:14 -07:00
[ userPreferences setInteger : -1 forKey : @ "selectedIntelligence" ] ;
2012-07-09 17:32:22 -07:00
[ userPreferences synchronize ] ;
2012-12-20 12:08:35 -08:00
direction = -1 ;
2012-07-09 17:42:32 -07:00
self . viewShowingAllFeeds = YES ;
2012-12-20 12:08:35 -08:00
[ appDelegate setSelectedIntelligence : 0 ] ;
2016-03-26 21:27:25 -07:00
} else if ( selectedSegmentIndex = = 1 ) {
2012-07-12 22:05:23 -07:00
hud . labelText = @ "Unread Stories" ;
2012-07-16 19:45:14 -07:00
[ userPreferences setInteger : 0 forKey : @ "selectedIntelligence" ] ;
2012-07-09 17:32:22 -07:00
[ userPreferences synchronize ] ;
2012-12-20 12:08:35 -08:00
direction = self . viewShowingAllFeeds ? 1 : -1 ;
2012-07-09 17:42:32 -07:00
self . viewShowingAllFeeds = NO ;
2012-12-20 12:08:35 -08:00
[ appDelegate setSelectedIntelligence : 0 ] ;
2016-03-26 21:27:25 -07:00
} else if ( selectedSegmentIndex = = 2 ) {
2012-07-12 22:05:23 -07:00
hud . labelText = @ "Focus Stories" ;
2012-07-16 19:45:14 -07:00
[ userPreferences setInteger : 1 forKey : @ "selectedIntelligence" ] ;
2012-07-09 17:32:22 -07:00
[ userPreferences synchronize ] ;
2012-12-20 12:08:35 -08:00
direction = 1 ;
self . viewShowingAllFeeds = NO ;
2012-07-09 17:32:22 -07:00
[ appDelegate setSelectedIntelligence : 1 ] ;
2016-03-26 21:27:25 -07:00
} else {
hud . labelText = @ "Saved Stories" ;
[ userPreferences setInteger : 2 forKey : @ "selectedIntelligence" ] ;
[ userPreferences synchronize ] ;
direction = 1 ;
self . viewShowingAllFeeds = NO ;
[ appDelegate setSelectedIntelligence : 2 ] ;
2011-08-24 21:44:16 -07:00
}
2015-12-07 16:09:49 -08:00
2012-12-20 12:08:35 -08:00
[ self calculateFeedLocations ] ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2012-06-26 12:29:37 -07:00
2012-12-20 12:08:35 -08:00
NSIndexPath * newMiddleRow ;
2013-02-06 18:42:15 -08:00
if ( topRow && [ self . feedTitlesTable numberOfRowsInSection : topRow . section ] = = 0 ) {
2012-12-20 12:08:35 -08:00
newMiddleRow = [ [ self . feedTitlesTable indexPathsForVisibleRows ] objectAtIndex : 0 ] ;
2013-02-06 18:42:15 -08:00
} else if ( topRow ) {
2012-12-20 12:08:35 -08:00
newMiddleRow = [ NSIndexPath indexPathForRow : 0 inSection : topRow . section ] ;
}
2013-02-06 18:42:15 -08:00
if ( newMiddleRow ) {
[ self . feedTitlesTable scrollToRowAtIndexPath : newMiddleRow
atScrollPosition : UITableViewScrollPositionTop
animated : NO ] ;
}
2012-12-20 12:08:35 -08:00
[ self . feedTitlesTable
reloadRowsAtIndexPaths : [ self . feedTitlesTable indexPathsForVisibleRows ]
withRowAnimation : direction = = 1 ? UITableViewRowAnimationLeft : UITableViewRowAnimationRight ] ;
2013-10-18 14:17:01 -07:00
for ( UITableViewCell * cell in self . feedTitlesTable . visibleCells ) {
[ cell setNeedsDisplay ] ;
}
2012-12-20 12:08:35 -08:00
[ hud hide : YES afterDelay : 0.5 ] ;
2013-03-28 14:21:14 -07:00
[ self showExplainerOnEmptyFeedlist ] ;
2014-02-28 13:11:12 -08:00
2020-08-29 21:19:32 -07:00
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
// FeedDetailViewController * storiesModule = self . appDelegate . dashboardViewController . storiesModule ;
//
// storiesModule . storiesCollection . feedPage = 0 ;
// storiesModule . storiesCollection . storyCount = 0 ;
// storiesModule . pageFinished = NO ;
// [ storiesModule . storiesCollection calculateStoryLocations ] ;
// [ storiesModule reloadData ] ;
// }
2013-03-28 14:21:14 -07:00
}
- ( void ) showExplainerOnEmptyFeedlist {
NSInteger intelligenceLevel = [ appDelegate selectedIntelligence ] ;
if ( intelligenceLevel > 0 ) {
BOOL hasFocusStory = NO ;
2013-06-29 17:28:41 -07:00
for ( id feedId in appDelegate . dictUnreadCounts ) {
NSDictionary * unreadCounts = [ appDelegate . dictUnreadCounts objectForKey : feedId ] ;
if ( [ [ unreadCounts objectForKey : @ "ps" ] intValue ] > 0 ) {
2013-03-28 14:21:14 -07:00
hasFocusStory = YES ;
break ;
}
}
if ( ! hasFocusStory ) {
2013-04-12 13:06:47 -07:00
self . noFocusMessage . hidden = NO ;
} else {
self . noFocusMessage . hidden = YES ;
2013-03-28 14:21:14 -07:00
}
2013-04-12 13:06:47 -07:00
} else {
self . noFocusMessage . hidden = YES ;
2013-03-28 14:21:14 -07:00
}
2017-11-15 10:55:16 -08:00
if ( appDelegate . isSavedStoriesIntelligenceMode ) {
self . noFocusLabel . text = @ "You have no saved stories." ;
} else {
self . noFocusLabel . text = @ "You have no unread stories in Focus mode." ;
}
2011-08-02 10:13:06 -07:00
}
2011-08-27 15:53:51 -07:00
- ( void ) redrawUnreadCounts {
2013-10-17 17:23:52 -07:00
FeedTableCell * cell = ( FeedTableCell * ) [ self . feedTitlesTable
cellForRowAtIndexPath : self . currentRowAtIndexPath ] ;
if ( cell ) {
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : self . currentRowAtIndexPath . section ] ;
2020-05-27 21:26:44 -07:00
if ( [ folderName isEqualToString : @ "saved_searches" ] ) {
return ;
}
2013-10-17 17:23:52 -07:00
id feedId = [ [ appDelegate . dictFolders objectForKey : folderName ] objectAtIndex : self . currentRowAtIndexPath . row ] ;
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
NSDictionary * unreadCounts = [ appDelegate . dictUnreadCounts objectForKey : feedIdStr ] ;
2014-02-28 17:52:07 -08:00
if ( ! [ cell respondsToSelector : @ selector ( setPositiveCount : ) ] ) return ;
2014-02-24 18:35:35 -08:00
[ cell setPositiveCount : [ [ unreadCounts objectForKey : @ "ps" ] intValue ] ] ;
[ cell setNeutralCount : [ [ unreadCounts objectForKey : @ "nt" ] intValue ] ] ;
[ cell setNegativeCount : [ [ unreadCounts objectForKey : @ "ng" ] intValue ] ] ;
2013-10-17 17:23:52 -07:00
} else {
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2012-10-07 15:47:21 -04:00
}
2011-08-27 15:53:51 -07:00
}
2016-11-24 16:41:41 -05:00
- ( void ) resetupGestures {
while ( [ self . feedTitlesTable dequeueReusableCellWithIdentifier : @ "FeedCellIdentifier" ] ) { }
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2016-11-24 16:41:41 -05:00
}
2012-12-20 12:08:35 -08:00
- ( void ) calculateFeedLocations {
2011-08-02 10:13:06 -07:00
self . activeFeedLocations = [ NSMutableDictionary dictionary ] ;
2012-12-20 12:08:35 -08:00
self . visibleFolders = [ NSMutableDictionary dictionary ] ;
2011-10-04 18:01:35 -07:00
for ( NSString * folderName in appDelegate . dictFoldersArray ) {
2012-12-07 15:17:22 -08:00
if ( [ folderName isEqualToString : @ "river_global" ] ) continue ;
2011-10-04 18:01:35 -07:00
NSArray * folder = [ appDelegate . dictFolders objectForKey : folderName ] ;
2011-08-24 21:44:16 -07:00
NSMutableArray * feedLocations = [ NSMutableArray array ] ;
2012-06-26 11:45:42 -07:00
for ( int f = 0 ; f < [ folder count ] ; f + + ) {
2011-08-24 21:44:16 -07:00
id feedId = [ folder objectAtIndex : f ] ;
2012-12-20 12:08:35 -08:00
if ( [ self isFeedVisible : feedId ] ) {
2011-08-24 21:44:16 -07:00
NSNumber * location = [ NSNumber numberWithInt : f ] ;
[ feedLocations addObject : location ] ;
2012-12-20 12:08:35 -08:00
if ( ! [ [ self . visibleFolders objectForKey : folderName ] boolValue ] ) {
[ self . visibleFolders setObject : [ NSNumber numberWithBool : YES ] forKey : folderName ] ;
2011-08-24 21:44:16 -07:00
}
}
}
[ self . activeFeedLocations setObject : feedLocations forKey : folderName ] ;
}
2011-08-02 09:16:54 -07:00
}
2011-08-02 18:03:11 -07:00
+ ( int ) computeMaxScoreForFeed : ( NSDictionary * ) feed {
2011-08-24 21:44:16 -07:00
int maxScore = -2 ;
if ( [ [ feed objectForKey : @ "ng" ] intValue ] > 0 ) maxScore = -1 ;
if ( [ [ feed objectForKey : @ "nt" ] intValue ] > 0 ) maxScore = 0 ;
if ( [ [ feed objectForKey : @ "ps" ] intValue ] > 0 ) maxScore = 1 ;
return maxScore ;
2011-08-02 18:03:11 -07:00
}
2011-08-04 17:58:28 -07:00
# pragma mark -
# pragma mark Favicons
- ( void ) loadFavicons {
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/reader/favicons" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2017-03-24 17:30:46 -07:00
2019-08-22 12:03:39 -07:00
[ appDelegate GET : urlString parameters : nil target : self success : @ selector ( saveAndDrawFavicons : ) failure : @ selector ( requestFailed : ) ] ;
2011-08-04 17:58:28 -07:00
}
2012-06-26 11:45:42 -07:00
- ( void ) loadAvatars {
2014-02-03 18:54:50 -08:00
dispatch_queue _t queue = dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _LOW , 0 ul ) ;
2012-06-26 11:45:42 -07:00
dispatch_async ( queue , ^ {
2020-08-27 15:08:46 -07:00
for ( NSString * feed_id in [ self . appDelegate . dictSocialFeeds allKeys ] ) {
NSDictionary * feed = [ self . appDelegate . dictSocialFeeds objectForKey : feed_id ] ;
2012-07-11 10:33:39 -07:00
NSURL * imageURL = [ NSURL URLWithString : [ feed objectForKey : @ "photo_url" ] ] ;
2012-06-26 11:45:42 -07:00
NSData * imageData = [ NSData dataWithContentsOfURL : imageURL ] ;
2013-12-11 18:06:22 -08:00
if ( ! imageData ) continue ;
2012-06-26 11:45:42 -07:00
UIImage * faviconImage = [ UIImage imageWithData : imageData ] ;
2013-12-11 18:06:22 -08:00
if ( ! faviconImage ) continue ;
2012-07-11 18:08:07 -07:00
faviconImage = [ Utilities roundCorneredImage : faviconImage radius : 6 ] ;
2012-07-02 10:45:25 -07:00
2020-08-27 15:08:46 -07:00
[ self . appDelegate saveFavicon : faviconImage feedId : feed_id ] ;
2012-06-26 11:45:42 -07:00
}
2014-02-24 18:35:35 -08:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2012-06-26 11:45:42 -07:00
} ) ;
} ) ;
}
2012-07-11 18:08:07 -07:00
2012-07-02 10:45:25 -07:00
2017-03-24 17:30:46 -07:00
- ( void ) saveAndDrawFavicons : ( NSDictionary * ) results {
2014-02-03 18:54:50 -08:00
dispatch_queue _t queue = dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _LOW , 0 ul ) ;
2011-10-18 08:56:13 -07:00
dispatch_async ( queue , ^ {
for ( id feed_id in results ) {
2014-03-03 22:36:40 -08:00
// NSMutableDictionary * feed = [ [ appDelegate . dictFeeds objectForKey : feed_id ] mutableCopy ] ;
// [ feed setValue : [ results objectForKey : feed_id ] forKey : @ "favicon" ] ;
// [ appDelegate . dictFeeds setValue : feed forKey : feed_id ] ;
2011-10-18 08:56:13 -07:00
2020-08-27 15:08:46 -07:00
if ( ! [ self . appDelegate . dictFeeds objectForKey : feed_id ] ) continue ;
2014-03-03 22:36:40 -08:00
NSString * favicon = [ results objectForKey : feed_id ] ;
2011-10-18 08:56:13 -07:00
if ( ( NSNull * ) favicon ! = [ NSNull null ] && [ favicon length ] > 0 ) {
2017-11-30 16:57:10 -08:00
NSData * imageData = [ [ NSData alloc ] initWithBase64EncodedString : favicon options : NSDataBase64DecodingIgnoreUnknownCharacters ] ;
// NSData * imageData = [ NSData dataWithBase64EncodedString : favicon ] ;
2011-10-18 08:56:13 -07:00
UIImage * faviconImage = [ UIImage imageWithData : imageData ] ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate saveFavicon : faviconImage feedId : feed_id ] ;
2011-10-18 08:56:13 -07:00
}
2011-10-14 16:35:40 -07:00
}
2014-03-03 22:36:40 -08:00
2014-02-24 18:35:35 -08:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2014-02-12 15:48:16 -08:00
[ self loadAvatars ] ;
2011-10-18 08:56:13 -07:00
} ) ;
} ) ;
2011-08-04 17:58:28 -07:00
}
2017-03-24 17:30:46 -07:00
- ( void ) requestFailed : ( NSError * ) error {
2011-08-04 17:58:28 -07:00
NSLog ( @ "Error: %@" , error ) ;
2013-03-06 14:29:40 -08:00
[ appDelegate informError : error ] ;
2011-08-04 17:58:28 -07:00
}
2018-08-29 14:55:37 -07:00
# pragma mark -
# pragma mark Search
- ( BOOL ) searchBarShouldBeginEditing : ( UISearchBar * ) searchBar {
[ self updateTheme ] ;
return YES ;
}
- ( void ) searchBarTextDidBeginEditing : ( UISearchBar * ) searchBar {
[ self . searchBar setShowsCancelButton : YES animated : YES ] ;
}
- ( void ) searchBarTextDidEndEditing : ( UISearchBar * ) searchBar {
if ( [ self . searchBar . text length ] ) {
[ self . searchBar setShowsCancelButton : YES animated : YES ] ;
} else {
[ self . searchBar setShowsCancelButton : NO animated : YES ] ;
}
[ self . searchBar resignFirstResponder ] ;
}
- ( void ) searchBarCancelButtonClicked : ( UISearchBar * ) searchBar {
[ self . searchBar setText : @ "" ] ;
[ self . searchBar resignFirstResponder ] ;
self . searchFeedIds = nil ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2018-08-29 14:55:37 -07:00
}
- ( void ) searchBarSearchButtonClicked : ( UISearchBar * ) theSearchBar {
[ self . searchBar resignFirstResponder ] ;
}
- ( BOOL ) disablesAutomaticKeyboardDismissal {
return NO ;
}
- ( void ) searchBar : ( UISearchBar * ) searchBar textDidChange : ( NSString * ) searchText {
if ( searchText . length ) {
NSMutableArray * array = [ NSMutableArray array ] ;
for ( NSString * folderName in appDelegate . dictFoldersArray ) {
NSArray * folder = [ appDelegate . dictFolders objectForKey : folderName ] ;
for ( id feedId in folder ) {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feedId ] ;
NSDictionary * feed = [ appDelegate getFeed : feedIdStr ] ;
NSString * title = [ feed objectForKey : @ "feed_title" ] ;
if ( [ title localizedStandardContainsString : searchText ] ) {
[ array addObject : feedIdStr ] ;
}
}
}
NSLog ( @ "search: '%@' matches %@ feeds" , searchText , @ ( array . count ) ) ; // log
if ( array . count ) {
self . searchFeedIds = array ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2018-08-29 14:55:37 -07:00
}
} else {
self . searchFeedIds = nil ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2018-08-29 14:55:37 -07:00
}
}
2011-08-04 17:58:28 -07:00
# pragma mark -
# pragma mark PullToRefresh
2016-09-13 15:38:51 -07:00
- ( void ) refresh : ( UIRefreshControl * ) refreshControl {
2012-08-16 20:10:50 -07:00
self . inPullToRefresh_ = YES ;
2013-10-11 17:46:09 -07:00
[ appDelegate reloadFeedsView : NO ] ;
2019-04-24 20:32:04 -07:00
[ appDelegate donateRefresh ] ;
2012-07-02 11:42:06 -07:00
}
2016-10-06 21:58:16 -07:00
- ( void ) finishRefresh {
self . inPullToRefresh_ = NO ;
[ self . refreshControl endRefreshing ] ;
2012-07-02 11:42:06 -07:00
}
- ( void ) refreshFeedList {
2012-12-10 20:22:21 -08:00
[ self refreshFeedList : nil ] ;
}
- ( void ) refreshFeedList : ( id ) feedId {
2012-06-29 17:37:49 -07:00
// refresh the feed
2012-12-10 20:22:21 -08:00
NSString * urlString ;
2016-03-26 21:27:25 -07:00
2012-12-10 20:22:21 -08:00
if ( feedId ) {
2013-06-18 21:23:20 -04:00
urlString = [ NSString stringWithFormat : @ "%@/reader/feed_unread_count?feed_id=%@" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url , feedId ] ;
2012-12-10 20:22:21 -08:00
} else {
2013-06-18 21:23:20 -04:00
urlString = [ NSString stringWithFormat : @ "%@/reader/refresh_feeds" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2012-12-10 20:22:21 -08:00
}
2012-06-29 17:37:49 -07:00
2013-10-09 14:54:49 -07:00
if ( ! feedId ) {
[ self . appDelegate cancelOfflineQueue ] ;
}
2013-06-29 17:28:41 -07:00
2019-08-22 12:03:39 -07:00
[ appDelegate GET : urlString parameters : nil success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-03-24 17:30:46 -07:00
[ self finishRefreshingFeedList : responseObject feedId : feedId ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
NSHTTPURLResponse * httpResponse = ( NSHTTPURLResponse * ) task . response ;
2017-06-01 21:19:54 -07:00
[ self finishRefresh ] ;
2017-03-24 17:30:46 -07:00
if ( [ httpResponse statusCode ] = = 403 ) {
NSLog ( @ "Showing login after refresh" ) ;
2020-08-27 15:08:46 -07:00
return [ self . appDelegate showLogin ] ;
2017-03-24 17:30:46 -07:00
} else if ( [ httpResponse statusCode ] = = 503 ) {
return [ self informError : @ "In maintenance mode" ] ;
} else if ( [ httpResponse statusCode ] >= 500 ) {
return [ self informError : @ "The server barfed!" ] ;
}
2017-06-01 21:19:54 -07:00
2017-03-24 17:30:46 -07:00
[ self requestFailed : error ] ;
} ] ;
2013-06-23 22:19:08 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2013-10-09 14:54:49 -07:00
if ( ! feedId ) {
[ self showCountingNotifier ] ;
}
2013-06-23 22:19:08 -07:00
} ) ;
2013-07-18 18:24:38 -07:00
2012-06-29 17:37:49 -07:00
}
2017-03-24 17:30:46 -07:00
- ( void ) finishRefreshingFeedList : ( NSDictionary * ) results feedId : ( NSString * ) feedId {
2013-10-17 17:23:52 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _DEFAULT ,
( unsigned long ) NULL ) , ^ ( void ) {
NSDictionary * newFeedCounts = [ results objectForKey : @ "feeds" ] ;
2020-08-27 15:08:46 -07:00
NSInteger intelligenceLevel = [ self . appDelegate selectedIntelligence ] ;
2013-10-17 17:23:52 -07:00
for ( id feed in newFeedCounts ) {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feed ] ;
2020-08-27 15:08:46 -07:00
NSMutableDictionary * unreadCount = [ [ self . appDelegate . dictUnreadCounts objectForKey : feedIdStr ] mutableCopy ] ;
2013-10-17 17:23:52 -07:00
NSMutableDictionary * newFeedCount = [ newFeedCounts objectForKey : feed ] ;
if ( ! [ unreadCount isKindOfClass : [ NSDictionary class ] ] ) continue ;
// Check if a feed goes from visible to hidden , but doesn ' t disappear .
if ( ( intelligenceLevel > 0 &&
[ [ unreadCount objectForKey : @ "ps" ] intValue ] > 0 &&
[ [ newFeedCount objectForKey : @ "ps" ] intValue ] = = 0 ) ||
( intelligenceLevel = = 0 &&
( [ [ unreadCount objectForKey : @ "ps" ] intValue ] > 0 ||
[ [ unreadCount objectForKey : @ "nt" ] intValue ] > 0 ) &&
[ [ newFeedCount objectForKey : @ "ps" ] intValue ] = = 0 &&
[ [ newFeedCount objectForKey : @ "nt" ] intValue ] = = 0 ) ) {
NSIndexPath * indexPath ;
2020-08-27 15:08:46 -07:00
for ( int s = 0 ; s < [ self . appDelegate . dictFoldersArray count ] ; s + + ) {
NSString * folderName = [ self . appDelegate . dictFoldersArray objectAtIndex : s ] ;
2013-10-17 17:23:52 -07:00
NSArray * activeFolderFeeds = [ self . activeFeedLocations objectForKey : folderName ] ;
2020-08-27 15:08:46 -07:00
NSArray * originalFolder = [ self . appDelegate . dictFolders objectForKey : folderName ] ;
2013-10-17 17:23:52 -07:00
for ( int l = 0 ; l < [ activeFolderFeeds count ] ; l + + ) {
if ( [ [ originalFolder objectAtIndex : [ [ activeFolderFeeds objectAtIndex : l ] intValue ] ] intValue ] = = [ feed intValue ] ) {
indexPath = [ NSIndexPath indexPathForRow : l inSection : s ] ;
break ;
}
2012-11-26 15:51:50 -08:00
}
2013-10-17 17:23:52 -07:00
if ( indexPath ) break ;
}
if ( indexPath ) {
[ self . stillVisibleFeeds setObject : indexPath forKey : feedIdStr ] ;
2012-11-26 15:51:50 -08:00
}
}
2013-10-17 17:23:52 -07:00
[ unreadCount setObject : [ newFeedCount objectForKey : @ "ng" ] forKey : @ "ng" ] ;
[ unreadCount setObject : [ newFeedCount objectForKey : @ "nt" ] forKey : @ "nt" ] ;
[ unreadCount setObject : [ newFeedCount objectForKey : @ "ps" ] forKey : @ "ps" ] ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate . dictUnreadCounts setObject : unreadCount forKey : feedIdStr ] ;
2012-08-09 10:18:15 -07:00
}
2013-10-17 17:23:52 -07:00
NSDictionary * newSocialFeedCounts = [ results objectForKey : @ "social_feeds" ] ;
for ( id feed in newSocialFeedCounts ) {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" , feed ] ;
2020-08-27 15:08:46 -07:00
NSMutableDictionary * unreadCount = [ [ self . appDelegate . dictUnreadCounts objectForKey : feedIdStr ] mutableCopy ] ;
2013-10-17 17:23:52 -07:00
NSMutableDictionary * newFeedCount = [ newSocialFeedCounts objectForKey : feed ] ;
if ( ! [ unreadCount isKindOfClass : [ NSDictionary class ] ] ) continue ;
[ unreadCount setObject : [ newFeedCount objectForKey : @ "ng" ] forKey : @ "ng" ] ;
[ unreadCount setObject : [ newFeedCount objectForKey : @ "nt" ] forKey : @ "nt" ] ;
[ unreadCount setObject : [ newFeedCount objectForKey : @ "ps" ] forKey : @ "ps" ] ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate . dictUnreadCounts setObject : unreadCount forKey : feedIdStr ] ;
2013-10-17 17:23:52 -07:00
}
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2020-08-27 15:08:46 -07:00
[ self . appDelegate . folderCountCache removeAllObjects ] ;
2019-05-31 20:32:08 -07:00
[ self reloadFeedTitlesTable ] ;
2013-10-17 17:23:52 -07:00
[ self refreshHeaderCounts ] ;
2017-03-24 17:30:46 -07:00
if ( ! feedId ) {
2013-10-17 17:23:52 -07:00
[ self . appDelegate startOfflineQueue ] ;
}
2014-03-03 22:36:40 -08:00
[ self loadFavicons ] ;
2018-11-21 13:31:50 -08:00
// if ( ! self . searchFeedIds && self . feedTitlesTable . contentOffset . y = = 0 ) {
// [ UIView animateWithDuration : 0.2 animations : ^ {
// self . feedTitlesTable . contentOffset = CGPointMake ( 0 , CGRectGetHeight ( self . searchBar . frame ) ) ;
// } ] ;
//
// }
2013-10-17 17:23:52 -07:00
} ) ;
} ) ;
2011-08-04 17:58:28 -07:00
}
2012-08-14 17:20:45 -07:00
- ( void ) resetToolbar {
2020-10-30 20:58:27 -07:00
// self . navigationItem . leftBarButtonItem = nil ;
2012-08-14 17:20:45 -07:00
self . navigationItem . titleView = nil ;
self . navigationItem . rightBarButtonItem = nil ;
}
2013-10-17 17:23:52 -07:00
- ( void ) layoutHeaderCounts : ( UIInterfaceOrientation ) orientation {
if ( ! orientation ) {
2020-09-25 20:31:01 -07:00
orientation = self . view . window . windowScene . interfaceOrientation ;
2013-10-17 17:23:52 -07:00
}
2013-10-03 13:54:15 -07:00
BOOL isShort = NO ;
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone &&
2013-03-03 17:37:54 -08:00
UIInterfaceOrientationIsLandscape ( orientation ) ) {
2013-10-03 13:54:15 -07:00
isShort = YES ;
2013-03-03 15:41:59 -08:00
}
2013-10-17 17:23:52 -07:00
2013-10-03 13:54:15 -07:00
int yOffset = isShort ? 0 : 6 ;
UIView * userInfoView = [ [ UIView alloc ]
initWithFrame : CGRectMake ( 0 , 0 ,
2021-07-05 21:58:57 -07:00
self . navigationController . navigationBar . frame . size . width ,
self . navigationController . navigationBar . frame . size . height ) ] ;
2013-09-25 17:43:00 -07:00
// adding user avatar to left
NSURL * imageURL = [ NSURL URLWithString : [ NSString stringWithFormat : @ "%@" ,
[ appDelegate . dictSocialProfile
2013-12-06 16:29:15 -08:00
objectForKey : @ "large_photo_url" ] ] ] ;
2020-10-30 20:58:27 -07:00
userAvatarButton = [ UIButton systemButtonWithImage : [ UIImage imageNamed : @ "user" ]
target : self action : @ selector ( ( showUserProfile ) ) ] ;
userAvatarButton . pointerInteractionEnabled = YES ;
2015-11-04 20:06:46 -08:00
userAvatarButton . accessibilityLabel = @ "User info" ;
userAvatarButton . accessibilityHint = @ "Double-tap for information about your account." ;
2022-10-26 13:20:36 -06:00
UIEdgeInsets insets = UIEdgeInsetsMake ( 0 , -10 , 10 , 0 ) ;
2022-10-20 11:24:15 -06:00
userAvatarButton . contentEdgeInsets = insets ;
2020-10-30 20:58:27 -07:00
2015-09-18 15:02:15 -07:00
NSMutableURLRequest * avatarRequest = [ NSMutableURLRequest requestWithURL : imageURL ] ;
[ avatarRequest addValue : @ "image/*" forHTTPHeaderField : @ "Accept" ] ;
[ avatarRequest setTimeoutInterval : 30.0 ] ;
2020-10-30 20:58:27 -07:00
avatarImageView = [ [ UIImageView alloc ] initWithFrame : userAvatarButton . frame ] ;
2015-09-18 15:29:57 -07:00
typeof ( self ) __weak weakSelf = self ;
2013-09-25 17:43:00 -07:00
[ avatarImageView setImageWithURLRequest : avatarRequest placeholderImage : nil success : ^ ( NSURLRequest * request , NSHTTPURLResponse * response , UIImage * image ) {
2015-09-18 15:29:57 -07:00
typeof ( weakSelf ) __strong strongSelf = weakSelf ;
2022-10-20 11:24:15 -06:00
image = [ Utilities roundCorneredImage : image radius : 6 convertToSize : CGSizeMake ( 38 , 38 ) ] ;
2020-10-30 20:58:27 -07:00
image = [ image imageWithRenderingMode : UIImageRenderingModeAlwaysOriginal ] ;
[ ( UIButton * ) strongSelf . userAvatarButton setImage : image forState : UIControlStateNormal ] ;
2017-10-03 18:39:06 -07:00
2015-09-18 15:02:15 -07:00
} failure : ^ ( NSURLRequest * _Nonnull request , NSHTTPURLResponse * _Nonnull response , NSError * _Nonnull error ) {
NSLog ( @ "Could not fetch user avatar: %@" , error ) ;
} ] ;
2020-10-30 20:58:27 -07:00
[ userInfoView addSubview : userAvatarButton ] ;
2015-09-18 15:02:15 -07:00
2022-10-26 13:20:36 -06:00
userLabel = [ [ UILabel alloc ] initWithFrame : CGRectMake ( 50 , yOffset , userInfoView . frame . size . width , 16 ) ] ;
2013-02-15 16:41:20 -08:00
userLabel . text = appDelegate . activeUsername ;
2013-10-18 18:37:11 -07:00
userLabel . font = userLabelFont ;
2013-02-15 16:41:20 -08:00
userLabel . textColor = UIColorFromRGB ( 0 x404040 ) ;
userLabel . backgroundColor = [ UIColor clearColor ] ;
2015-11-04 20:06:46 -08:00
userLabel . accessibilityLabel = [ NSString stringWithFormat : @ "Logged in as %@" , appDelegate . activeUsername ] ;
2013-10-11 17:46:09 -07:00
[ userLabel sizeToFit ] ;
2013-02-15 16:41:20 -08:00
[ userInfoView addSubview : userLabel ] ;
[ appDelegate . folderCountCache removeObjectForKey : @ "everything" ] ;
2017-10-04 14:42:10 -07:00
yellowIcon = [ [ UIImageView alloc ] initWithImage : [ UIImage imageNamed : @ "g_icn_unread" ] ] ;
[ userInfoView addSubview : yellowIcon ] ;
2021-04-22 21:49:13 -07:00
yellowIcon . hidden = YES ;
2013-02-15 16:41:20 -08:00
2013-10-17 17:23:52 -07:00
neutralCount = [ [ UILabel alloc ] init ] ;
2021-03-26 21:51:02 -07:00
neutralCount . font = [ UIFont fontWithName : @ "WhitneySSm-Book" size : 12 ] ;
2013-02-15 16:41:20 -08:00
neutralCount . textColor = UIColorFromRGB ( 0 x707070 ) ;
neutralCount . backgroundColor = [ UIColor clearColor ] ;
[ userInfoView addSubview : neutralCount ] ;
2013-10-17 17:23:52 -07:00
greenIcon = [ [ UIImageView alloc ] initWithImage : [ UIImage imageNamed : @ "g_icn_focus" ] ] ;
[ userInfoView addSubview : greenIcon ] ;
2021-04-22 21:49:13 -07:00
greenIcon . hidden = YES ;
2013-02-15 16:41:20 -08:00
2013-10-17 17:23:52 -07:00
positiveCount = [ [ UILabel alloc ] init ] ;
2021-03-26 21:51:02 -07:00
positiveCount . font = [ UIFont fontWithName : @ "WhitneySSm-Book" size : 12 ] ;
2013-02-15 16:41:20 -08:00
positiveCount . textColor = UIColorFromRGB ( 0 x707070 ) ;
positiveCount . backgroundColor = [ UIColor clearColor ] ;
[ userInfoView addSubview : positiveCount ] ;
2013-10-17 17:23:52 -07:00
2013-10-11 17:46:09 -07:00
[ userInfoView sizeToFit ] ;
2013-10-03 13:54:15 -07:00
2022-10-26 13:20:36 -06:00
// userInfoView . backgroundColor = UIColor . blueColor ;
2020-10-30 20:58:27 -07:00
self . navigationItem . titleView = userInfoView ;
2013-02-15 16:41:20 -08:00
}
2013-10-17 17:23:52 -07:00
- ( void ) refreshHeaderCounts {
if ( ! appDelegate . activeUsername ) {
2020-10-30 20:58:27 -07:00
userAvatarButton . hidden = YES ;
2013-10-17 17:23:52 -07:00
return ;
}
2020-10-30 20:58:27 -07:00
userAvatarButton . hidden = NO ;
2013-10-17 17:23:52 -07:00
[ appDelegate . folderCountCache removeObjectForKey : @ "everything" ] ;
NSNumberFormatter * formatter = [ NSNumberFormatter new ] ;
[ formatter setNumberStyle : NSNumberFormatterDecimalStyle ] ;
UnreadCounts * counts = [ appDelegate splitUnreadCountForFolder : @ "everything" ] ;
positiveCount . text = [ formatter stringFromNumber : [ NSNumber numberWithInt : counts . ps ] ] ;
2015-11-04 20:06:46 -08:00
positiveCount . accessibilityLabel = [ NSString stringWithFormat : @ "%@ focused stories" , positiveCount . text ] ;
2013-10-17 17:23:52 -07:00
neutralCount . text = [ formatter stringFromNumber : [ NSNumber numberWithInt : counts . nt ] ] ;
2015-11-04 20:06:46 -08:00
neutralCount . accessibilityLabel = [ NSString stringWithFormat : @ "%@ unread stories" , neutralCount . text ] ;
2017-10-04 14:42:10 -07:00
yellowIcon . frame = CGRectMake ( CGRectGetMinX ( userLabel . frame ) , CGRectGetMaxY ( userLabel . frame ) + 4 , 8 , 8 ) ;
neutralCount . frame = CGRectMake ( CGRectGetMaxX ( yellowIcon . frame ) + 2 ,
CGRectGetMinY ( yellowIcon . frame ) - 2 , 100 , 16 ) ;
2013-10-17 17:23:52 -07:00
[ neutralCount sizeToFit ] ;
2017-10-04 14:42:10 -07:00
greenIcon . frame = CGRectMake ( CGRectGetMaxX ( neutralCount . frame ) + 8 ,
CGRectGetMinY ( yellowIcon . frame ) , 8 , 8 ) ;
positiveCount . frame = CGRectMake ( CGRectGetMaxX ( greenIcon . frame ) + 2 ,
CGRectGetMinY ( greenIcon . frame ) - 2 , 100 , 16 ) ;
2013-10-17 17:23:52 -07:00
[ positiveCount sizeToFit ] ;
2017-05-10 22:31:20 -07:00
2021-04-22 21:49:13 -07:00
yellowIcon . hidden = NO ;
greenIcon . hidden = NO ;
2017-05-10 22:31:20 -07:00
NSUserDefaults * prefs = [ NSUserDefaults standardUserDefaults ] ;
NSString * appUnreadBadge = [ prefs stringForKey : @ "app_unread_badge" ] ;
if ( [ appUnreadBadge isEqualToString : @ "unread" ] ) {
2017-10-04 14:55:09 -07:00
[ appDelegate registerForBadgeNotifications ] ;
2017-05-10 22:31:20 -07:00
[ UIApplication sharedApplication ] . applicationIconBadgeNumber = counts . ps + counts . nt ;
} else if ( [ appUnreadBadge isEqualToString : @ "focus" ] ) {
2017-10-04 14:55:09 -07:00
[ appDelegate registerForBadgeNotifications ] ;
2017-05-10 22:31:20 -07:00
[ UIApplication sharedApplication ] . applicationIconBadgeNumber = counts . ps ;
} else {
[ UIApplication sharedApplication ] . applicationIconBadgeNumber = 0 ;
}
2013-10-17 17:23:52 -07:00
}
2017-12-15 18:10:04 -08:00
- ( void ) redrawFeedCounts : ( id ) feedId {
NSIndexPath * indexPath = [ indexPathsForFeedIds objectForKey : feedId ] ;
NSString * folderName = [ appDelegate . dictFoldersArray objectAtIndex : indexPath . section ] ;
BOOL isFolderCollapsed = [ appDelegate isFolderCollapsed : folderName ] ;
if ( indexPath ) {
2019-05-31 20:32:08 -07:00
[ self resetRowHeights ] ;
2017-12-15 18:10:04 -08:00
[ self . feedTitlesTable beginUpdates ] ;
if ( isFolderCollapsed ) {
[ appDelegate . folderCountCache removeObjectForKey : folderName ] ;
NSIndexSet * indexSet = [ [ NSIndexSet alloc ] initWithIndex : indexPath . section ] ;
[ self . feedTitlesTable reloadSections : indexSet withRowAnimation : UITableViewRowAnimationNone ] ;
} else {
[ self . feedTitlesTable reloadRowsAtIndexPaths : @ [ indexPath ]
withRowAnimation : UITableViewRowAnimationNone ] ;
}
[ self . feedTitlesTable endUpdates ] ;
}
[ self refreshHeaderCounts ] ;
}
2013-06-23 22:19:08 -07:00
- ( void ) showRefreshNotifier {
2013-07-15 15:36:25 -07:00
self . notifier . style = NBSyncingStyle ;
self . notifier . title = @ "On its way..." ;
[ self . notifier setProgress : 0 ] ;
2018-11-13 14:56:44 -08:00
[ self . notifier show ] ;
2013-07-15 15:36:25 -07:00
}
- ( void ) showCountingNotifier {
2013-06-23 22:19:08 -07:00
self . notifier . style = NBSyncingStyle ;
self . notifier . title = @ "Counting is difficult..." ;
[ self . notifier setProgress : 0 ] ;
[ self . notifier show ] ;
2016-11-02 17:56:08 -07:00
[ self finishRefresh ] ;
2013-06-23 22:19:08 -07:00
}
- ( void ) showSyncingNotifier {
2013-06-16 21:39:38 -07:00
self . notifier . style = NBSyncingStyle ;
self . notifier . title = @ "Syncing stories..." ;
2013-06-19 20:26:04 -07:00
[ self . notifier setProgress : 0 ] ;
2013-06-16 21:39:38 -07:00
[ self . notifier show ] ;
2016-11-02 17:56:08 -07:00
[ self finishRefresh ] ;
2013-06-16 21:39:38 -07:00
}
2013-07-15 15:36:25 -07:00
- ( void ) showDoneNotifier {
self . notifier . style = NBDoneStyle ;
self . notifier . title = @ "All done" ;
[ self . notifier setProgress : 0 ] ;
[ self . notifier show ] ;
2016-10-06 21:58:16 -07:00
[ self finishRefresh ] ;
2013-07-15 15:36:25 -07:00
}
2017-04-11 16:15:18 -07:00
- ( void ) showSyncingNotifier : ( float ) progress hoursBack : ( NSInteger ) hours {
2013-06-16 21:39:38 -07:00
// [ self . notifier hide ] ;
self . notifier . style = NBSyncingProgressStyle ;
if ( hours < 2 ) {
2013-06-23 22:19:08 -07:00
self . notifier . title = @ "Storing past hour" ;
2013-06-16 21:39:38 -07:00
} else if ( hours < 24 ) {
2017-04-11 16:15:18 -07:00
self . notifier . title = [ NSString stringWithFormat : @ "Storing past %ld hours" , ( long ) hours ] ;
2013-06-16 21:39:38 -07:00
} else if ( hours < 48 ) {
self . notifier . title = @ "Storing yesterday" ;
} else {
2013-06-23 22:19:08 -07:00
self . notifier . title = [ NSString stringWithFormat : @ "Storing past %d days" , ( int ) round ( hours / 24. f ) ] ;
2013-06-16 21:39:38 -07:00
}
[ self . notifier setProgress : progress ] ;
[ self . notifier show ] ;
}
2019-10-25 20:52:51 -07:00
- ( void ) showCachingNotifier : ( NSString * ) prefix progress : ( float ) progress hoursBack : ( NSInteger ) hours {
2013-06-21 22:18:54 -07:00
// [ self . notifier hide ] ;
self . notifier . style = NBSyncingProgressStyle ;
if ( hours < 2 ) {
2019-10-25 20:52:51 -07:00
self . notifier . title = [ NSString stringWithFormat : @ "%@ from last hour" , prefix ] ;
2013-06-21 22:18:54 -07:00
} else if ( hours < 24 ) {
2019-10-25 20:52:51 -07:00
self . notifier . title = [ NSString stringWithFormat : @ "%@ from %ld hours ago" , prefix , ( long ) hours ] ;
2013-06-21 22:18:54 -07:00
} else if ( hours < 48 ) {
2019-10-25 20:52:51 -07:00
self . notifier . title = [ NSString stringWithFormat : @ "%@ from yesterday" , prefix ] ;
2013-06-21 22:18:54 -07:00
} else {
2019-10-25 20:52:51 -07:00
self . notifier . title = [ NSString stringWithFormat : @ "%@ from %d days ago" , prefix , ( int ) round ( hours / 24. f ) ] ;
2013-06-21 22:18:54 -07:00
}
[ self . notifier setProgress : progress ] ;
[ self . notifier show ] ;
}
2013-06-16 21:39:38 -07:00
- ( void ) showOfflineNotifier {
self . notifier . style = NBOfflineStyle ;
self . notifier . title = @ "Offline" ;
[ self . notifier show ] ;
}
- ( void ) hideNotifier {
2013-07-16 18:06:36 -07:00
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , 0.25 * NSEC_PER _SEC ) ,
2013-07-15 15:36:25 -07:00
dispatch_get _main _queue ( ) , ^ {
[ self . notifier hide ] ;
} ) ;
2013-06-16 21:39:38 -07:00
}
2012-07-31 13:10:26 -07:00
2016-09-13 15:38:51 -07:00
@ end