2012-11-05 15:12:42 -08:00
//
2020-09-26 20:30:35 -07:00
// DetailObjCViewController . m
2012-11-05 15:12:42 -08:00
// NewsBlur
//
// Created by Samuel Clay on 11 / 2 / 12.
// Copyright ( c ) 2012 NewsBlur . All rights reserved .
//
2020-09-26 20:30:35 -07:00
# import "DetailObjCViewController.h"
2012-11-05 17:16:10 -08:00
# import "NewsBlurAppDelegate.h"
# import "FontSettingsViewController.h"
# import "UserProfileViewController.h"
# import "ShareViewController.h"
# import "Utilities.h"
# import "NSString+HTML.h"
# import "NBContainerViewController.h"
# import "DataUtilities.h"
2015-09-16 16:53:07 -07:00
# import "SBJson4.h"
2013-02-27 18:04:03 -08:00
# import "UIBarButtonItem+Image.h"
2013-04-10 21:06:17 -07:00
# import "THCircularProgressView.h"
2013-06-16 08:15:40 -07:00
# import "FMDatabase.h"
2014-02-12 20:09:37 -08:00
# import "StoriesCollection.h"
2020-08-27 21:26:12 -07:00
# import "NewsBlur-Swift.h"
2020-02-23 15:21:32 -08:00
@ import WebKit ;
2012-11-05 15:12:42 -08:00
2020-09-26 20:30:35 -07:00
@ interface DetailObjCViewController ( )
2019-02-28 15:29:31 -08:00
2020-04-24 20:58:20 -07:00
@ property ( nonatomic ) CGFloat statusBarHeight ;
2020-07-31 16:10:09 -07:00
@ property ( nonatomic ) BOOL wasNavigationBarHidden ;
2019-02-28 15:29:31 -08:00
@ property ( nonatomic , strong ) NSTimer * autoscrollTimer ;
@ property ( nonatomic , strong ) NSTimer * autoscrollViewTimer ;
2019-03-22 20:55:22 -07:00
@ property ( nonatomic , strong ) NSString * restoringStoryId ;
2019-02-28 15:29:31 -08:00
@ end
2020-09-26 20:30:35 -07:00
@ implementation DetailObjCViewController
2012-11-05 15:12:42 -08:00
2020-09-23 21:30:31 -07:00
@ synthesize appDelegate ;
2020-10-30 20:58:27 -07:00
// @ synthesize currentPage , nextPage , previousPage ;
2013-04-10 21:06:17 -07:00
@ synthesize circularProgressView ;
2013-02-27 18:04:03 -08:00
@ synthesize separatorBarButton ;
@ synthesize spacerBarButton , spacer2BarButton , spacer3BarButton ;
2012-11-05 17:16:10 -08:00
@ synthesize buttonPrevious ;
@ synthesize buttonNext ;
@ synthesize buttonAction ;
2013-05-29 13:36:39 -07:00
@ synthesize buttonText ;
2013-07-19 18:19:30 -07:00
@ synthesize buttonSend ;
2012-11-05 17:16:10 -08:00
@ synthesize fontSettingsButton ;
@ synthesize originalStoryButton ;
@ synthesize subscribeButton ;
@ synthesize buttonBack ;
2013-09-26 19:26:10 -07:00
@ synthesize bottomSize ;
2015-09-23 13:02:25 -07:00
@ synthesize bottomSizeHeightConstraint ;
2012-11-05 17:16:10 -08:00
@ synthesize loadingIndicator ;
2012-11-07 17:54:16 -08:00
@ synthesize inTouchMove ;
2012-11-08 18:30:45 -08:00
@ synthesize isDraggingScrollview ;
2012-12-13 16:41:52 -08:00
@ synthesize waitingForNextUnreadFromServer ;
2012-11-09 14:13:44 -08:00
@ synthesize storyHUD ;
2012-11-14 17:31:52 -08:00
@ synthesize scrollingToPage ;
2013-03-06 14:29:40 -08:00
@ synthesize traverseView ;
2014-01-30 20:28:08 -08:00
@ synthesize isAnimatedIntoPlace ;
2013-04-26 13:51:03 -07:00
@ synthesize progressView , progressViewContainer ;
2013-03-07 10:55:23 -05:00
@ synthesize traversePinned , traverseFloating ;
2017-11-05 18:22:58 -08:00
@ synthesize traverseBottomConstraint ;
2017-11-06 20:09:31 -08:00
@ synthesize scrollBottomConstraint ;
2012-11-05 15:12:42 -08:00
- ( id ) initWithNibName : ( NSString * ) nibNameOrNil bundle : ( NSBundle * ) nibBundleOrNil {
self = [ super initWithNibName : nibNameOrNil bundle : nibBundleOrNil ] ;
if ( self ) {
// Custom initialization
}
return self ;
}
2012-11-05 18:23:45 -08:00
- ( void ) viewDidLoad {
2014-09-18 11:25:51 -07:00
[ super viewDidLoad ] ;
2017-04-03 16:07:01 -07:00
appDelegate = [ NewsBlurAppDelegate sharedAppDelegate ] ;
2020-09-26 21:24:34 -07:00
2020-10-30 20:58:27 -07:00
# warning commented out for new UIPageViewController - based approach ; remove these in due course
// currentPage = [ [ StoryDetailViewController alloc ]
// initWithNibName : @ "StoryDetailViewController"
// bundle : nil ] ;
// nextPage = [ [ StoryDetailViewController alloc ]
// initWithNibName : @ "StoryDetailViewController"
// bundle : nil ] ;
// previousPage = [ [ StoryDetailViewController alloc ]
// initWithNibName : @ "StoryDetailViewController"
// bundle : nil ] ;
// currentPage . appDelegate = appDelegate ;
// nextPage . appDelegate = appDelegate ;
// previousPage . appDelegate = appDelegate ;
2020-09-26 20:30:35 -07:00
// currentPage . view . frame = self . scrollView . frame ;
// nextPage . view . frame = self . scrollView . frame ;
// previousPage . view . frame = self . scrollView . frame ;
2012-11-14 17:31:52 -08:00
2015-12-01 16:51:18 -08:00
// NSLog ( @ "Scroll view content inset: %@" , NSStringFromCGRect ( self . scrollView . bounds ) ) ;
// NSLog ( @ "Scroll view frame pre: %@" , NSStringFromCGRect ( self . scrollView . frame ) ) ;
2020-10-30 20:58:27 -07:00
// [ self . scrollView addSubview : currentPage . view ] ;
// [ self . scrollView addSubview : nextPage . view ] ;
// [ self . scrollView addSubview : previousPage . view ] ;
// [ self addChildViewController : currentPage ] ;
// [ self addChildViewController : nextPage ] ;
// [ self addChildViewController : previousPage ] ;
2012-11-05 15:12:42 -08:00
[ self . scrollView setPagingEnabled : YES ] ;
[ self . scrollView setScrollEnabled : YES ] ;
[ self . scrollView setShowsHorizontalScrollIndicator : NO ] ;
[ self . scrollView setShowsVerticalScrollIndicator : NO ] ;
2018-08-30 16:33:42 -07:00
[ self . scrollView setAlwaysBounceHorizontal : self . isHorizontal ] ;
[ self . scrollView setAlwaysBounceVertical : ! self . isHorizontal ] ;
2018-11-29 13:35:44 -08:00
2020-09-25 20:31:01 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
self . scrollView . contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever ;
2018-11-29 13:35:44 -08:00
}
2015-12-01 16:51:18 -08:00
// NSLog ( @ "Scroll view frame post: %@" , NSStringFromCGRect ( self . scrollView . frame ) ) ;
// NSLog ( @ "Scroll view parent: %@" , NSStringFromCGRect ( currentPage . view . frame ) ) ;
2015-03-12 19:43:39 -07:00
[ self . scrollView sizeToFit ] ;
2015-12-01 16:51:18 -08:00
// NSLog ( @ "Scroll view frame post 2: %@" , NSStringFromCGRect ( self . scrollView . frame ) ) ;
2012-11-05 17:16:10 -08:00
2020-09-25 20:31:01 -07:00
self . statusBarHeight = self . view . window . windowScene . statusBarManager . statusBarFrame . size . height ;
2020-04-24 20:58:20 -07:00
2015-12-15 12:37:18 -08:00
// adding HUD for progress bar
2013-04-12 13:06:47 -07:00
CGFloat radius = 8 ;
2013-04-10 21:06:17 -07:00
circularProgressView = [ [ THCircularProgressView alloc ]
2013-05-30 16:31:57 -07:00
initWithCenter : CGPointMake ( self . buttonNext . frame . origin . x + 2 * radius ,
2013-04-10 21:06:17 -07:00
self . traverseView . frame . size . height / 2 )
radius : radius
lineWidth : radius / 4.0 f
progressMode : THProgressModeFill
2013-04-12 13:06:47 -07:00
progressColor : [ UIColor colorWithRed : 0.612 f green : 0.62 f blue : 0.596 f alpha : 0.4 f ]
2013-04-10 21:06:17 -07:00
progressBackgroundMode : THProgressBackgroundModeCircumference
2013-07-19 17:53:52 -07:00
progressBackgroundColor : [ UIColor colorWithRed : 0.312 f green : 0.32 f blue : 0.296 f alpha : .04 f ]
2013-04-10 21:06:17 -07:00
percentage : 20 ] ;
2013-05-30 16:31:57 -07:00
circularProgressView . autoresizingMask = UIViewAutoresizingFlexibleLeftMargin ;
2013-04-10 21:06:17 -07:00
[ self . traverseView addSubview : circularProgressView ] ;
2013-10-03 13:54:15 -07:00
UIView * tapIndicator = [ [ UIView alloc ]
initWithFrame : CGRectMake ( circularProgressView . frame . origin . x -
circularProgressView . frame . size . width / 2 ,
circularProgressView . frame . origin . y -
circularProgressView . frame . size . height / 2 ,
circularProgressView . frame . size . width * 2 ,
circularProgressView . frame . size . height * 2 ) ] ;
UITapGestureRecognizer * tap = [ [ UITapGestureRecognizer alloc ]
initWithTarget : self
action : @ selector ( tapProgressBar : ) ] ;
2013-05-28 18:07:19 -07:00
[ tapIndicator addGestureRecognizer : tap ] ;
2013-05-30 16:31:57 -07:00
tapIndicator . autoresizingMask = UIViewAutoresizingFlexibleLeftMargin ;
2013-05-28 18:07:19 -07:00
[ self . traverseView insertSubview : tapIndicator aboveSubview : circularProgressView ] ;
2013-04-23 11:52:34 -07:00
self . loadingIndicator . frame = self . circularProgressView . frame ;
2013-04-10 21:06:17 -07:00
2013-02-27 18:04:03 -08:00
spacerBarButton = [ [ UIBarButtonItem alloc ]
2013-10-03 13:54:15 -07:00
initWithBarButtonSystemItem : UIBarButtonSystemItemFixedSpace
target : nil action : nil ] ;
2013-02-27 18:04:03 -08:00
spacerBarButton . width = -12 ;
spacer2BarButton = [ [ UIBarButtonItem alloc ]
2013-10-03 13:54:15 -07:00
initWithBarButtonSystemItem : UIBarButtonSystemItemFixedSpace
target : nil action : nil ] ;
spacer2BarButton . width = -6 ;
2013-02-27 18:04:03 -08:00
spacer3BarButton = [ [ UIBarButtonItem alloc ]
2013-10-03 13:54:15 -07:00
initWithBarButtonSystemItem : UIBarButtonSystemItemFixedSpace
target : nil action : nil ] ;
spacer3BarButton . width = -6 ;
2012-11-05 17:16:10 -08:00
2013-02-27 18:04:03 -08:00
UIImage * separatorImage = [ UIImage imageNamed : @ "bar-separator.png" ] ;
2016-03-01 12:31:22 -05:00
if ( [ ThemeManager themeManager ] . isDarkTheme ) {
separatorImage = [ UIImage imageNamed : @ "bar_separator_dark" ] ;
}
2013-10-03 13:54:15 -07:00
separatorBarButton = [ UIBarButtonItem barItemWithImage : separatorImage
target : nil
action : nil ] ;
2013-02-27 18:04:03 -08:00
[ separatorBarButton setEnabled : NO ] ;
2015-11-03 22:21:18 -08:00
separatorBarButton . isAccessibilityElement = NO ;
2012-11-05 17:16:10 -08:00
2013-02-27 18:04:03 -08:00
UIImage * settingsImage = [ UIImage imageNamed : @ "nav_icn_settings.png" ] ;
2013-10-03 13:54:15 -07:00
fontSettingsButton = [ UIBarButtonItem barItemWithImage : settingsImage
target : self
action : @ selector ( toggleFontSize : ) ] ;
2015-11-03 22:21:18 -08:00
fontSettingsButton . accessibilityLabel = @ "Story settings" ;
2012-11-05 17:16:10 -08:00
2013-02-27 18:04:03 -08:00
UIImage * markreadImage = [ UIImage imageNamed : @ "original_button.png" ] ;
2013-10-03 13:54:15 -07:00
originalStoryButton = [ UIBarButtonItem barItemWithImage : markreadImage
target : self
action : @ selector ( showOriginalSubview : ) ] ;
2015-11-03 22:21:18 -08:00
originalStoryButton . accessibilityLabel = @ "Show original story" ;
2017-11-01 22:19:26 -07:00
separatorBarButton2 = [ UIBarButtonItem barItemWithImage : separatorImage
target : nil
action : nil ] ;
[ separatorBarButton2 setEnabled : NO ] ;
separatorBarButton2 . isAccessibilityElement = NO ;
2012-11-05 17:16:10 -08:00
2017-11-01 22:19:26 -07:00
UIImage * markReadImage = [ UIImage imageNamed : @ "markread.png" ] ;
markReadBarButton = [ UIBarButtonItem barItemWithImage : markReadImage
target : self
action : @ selector ( markAllRead : ) ] ;
markReadBarButton . accessibilityLabel = @ "Mark all as read" ;
2012-11-05 17:16:10 -08:00
UIBarButtonItem * subscribeBtn = [ [ UIBarButtonItem alloc ]
initWithTitle : @ "Follow User"
2016-10-05 21:03:32 -07:00
style : UIBarButtonItemStylePlain
2012-11-05 17:16:10 -08:00
target : self
action : @ selector ( subscribeToBlurblog )
] ;
self . subscribeButton = subscribeBtn ;
// back button
UIBarButtonItem * backButton = [ [ UIBarButtonItem alloc ]
2013-10-03 13:54:15 -07:00
initWithTitle : @ "All Sites"
2015-09-16 16:53:07 -07:00
style : UIBarButtonItemStylePlain
2013-10-03 13:54:15 -07:00
target : self
action : @ selector ( transitionFromFeedDetail ) ] ;
2012-11-05 17:16:10 -08:00
self . buttonBack = backButton ;
2015-10-28 21:50:23 -07:00
self . notifier = [ [ NBNotifier alloc ] initWithTitle : @ "Fetching text..."
withOffset : CGPointMake ( 0.0 , 0.0 / * self . bottomSize . frame . size . height * / ) ] ;
[ self . view addSubview : self . notifier ] ;
2017-10-30 11:30:12 -07:00
[ self . view addConstraint : [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeWidth relatedBy : NSLayoutRelationEqual toItem : self . view attribute : NSLayoutAttributeWidth multiplier : 1.0 constant : 0 ] ] ;
[ self . view addConstraint : [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeLeading relatedBy : NSLayoutRelationEqual toItem : self . view attribute : NSLayoutAttributeLeading multiplier : 1.0 constant : 0 ] ] ;
[ 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:32:59 -07:00
self . notifier . topOffsetConstraint = [ NSLayoutConstraint constraintWithItem : self . notifier attribute : NSLayoutAttributeTop relatedBy : NSLayoutRelationEqual toItem : self . view attribute : NSLayoutAttributeBottom multiplier : 1.0 constant : 0 ] ;
[ self . view addConstraint : self . notifier . topOffsetConstraint ] ;
2015-10-28 21:50:23 -07:00
[ self . notifier hideNow ] ;
2012-11-05 17:16:10 -08:00
2020-05-26 14:13:46 -07:00
self . traverseBottomConstraint . constant = 50 ;
2020-08-25 21:46:23 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone ) {
2013-10-11 17:46:09 -07:00
self . navigationItem . rightBarButtonItems = [ NSArray arrayWithObjects :
originalStoryButton ,
separatorBarButton ,
fontSettingsButton , nil ] ;
2013-03-04 18:21:10 -08:00
}
2012-11-08 18:30:45 -08:00
[ self . scrollView addObserver : self forKeyPath : @ "contentOffset"
options : NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context : nil ] ;
2013-03-04 17:15:50 -08:00
2020-09-25 20:31:01 -07:00
_orientation = self . view . window . windowScene . interfaceOrientation ;
2019-03-22 20:55:22 -07:00
2015-11-24 15:04:14 -05:00
[ self addKeyCommandWithInput : UIKeyInputDownArrow modifierFlags : 0 action : @ selector ( changeToNextPage : ) discoverabilityTitle : @ "Next Story" ] ;
2015-11-21 23:23:37 -05:00
[ self addKeyCommandWithInput : @ "j" modifierFlags : 0 action : @ selector ( changeToNextPage : ) discoverabilityTitle : @ "Next Story" ] ;
2015-11-24 15:04:14 -05:00
[ self addKeyCommandWithInput : UIKeyInputUpArrow modifierFlags : 0 action : @ selector ( changeToPreviousPage : ) discoverabilityTitle : @ "Previous Story" ] ;
2015-11-21 23:23:37 -05:00
[ self addKeyCommandWithInput : @ "k" modifierFlags : 0 action : @ selector ( changeToPreviousPage : ) discoverabilityTitle : @ "Previous Story" ] ;
[ self addKeyCommandWithInput : @ "\r" modifierFlags : UIKeyModifierShift action : @ selector ( toggleTextView : ) discoverabilityTitle : @ "Text View" ] ;
[ self addKeyCommandWithInput : @ " " modifierFlags : 0 action : @ selector ( scrollPageDown : ) discoverabilityTitle : @ "Page Down" ] ;
[ self addKeyCommandWithInput : @ " " modifierFlags : UIKeyModifierShift action : @ selector ( scrollPageUp : ) discoverabilityTitle : @ "Page Up" ] ;
[ self addKeyCommandWithInput : @ "n" modifierFlags : 0 action : @ selector ( doNextUnreadStory : ) discoverabilityTitle : @ "Next Unread Story" ] ;
[ self addKeyCommandWithInput : @ "u" modifierFlags : 0 action : @ selector ( toggleStoryUnread : ) discoverabilityTitle : @ "Toggle Read/Unread" ] ;
[ self addKeyCommandWithInput : @ "m" modifierFlags : 0 action : @ selector ( toggleStoryUnread : ) discoverabilityTitle : @ "Toggle Read/Unread" ] ;
[ self addKeyCommandWithInput : @ "s" modifierFlags : 0 action : @ selector ( toggleStorySaved : ) discoverabilityTitle : @ "Save/Unsave Story" ] ;
[ self addKeyCommandWithInput : @ "o" modifierFlags : 0 action : @ selector ( showOriginalSubview : ) discoverabilityTitle : @ "Open in Browser" ] ;
[ self addKeyCommandWithInput : @ "v" modifierFlags : 0 action : @ selector ( showOriginalSubview : ) discoverabilityTitle : @ "Open in Browser" ] ;
[ self addKeyCommandWithInput : @ "s" modifierFlags : UIKeyModifierShift action : @ selector ( openShareDialog ) discoverabilityTitle : @ "Share This Story" ] ;
[ self addKeyCommandWithInput : @ "c" modifierFlags : 0 action : @ selector ( scrolltoComment ) discoverabilityTitle : @ "Scroll to Comments" ] ;
2015-11-24 15:39:07 -05:00
[ self addKeyCommandWithInput : @ "t" modifierFlags : 0 action : @ selector ( openStoryTrainerFromKeyboard : ) discoverabilityTitle : @ "Open Story Trainer" ] ;
2016-03-19 13:20:13 -04:00
[ self addCancelKeyCommandWithAction : @ selector ( backToDashboard : ) discoverabilityTitle : @ "Dashboard" ] ;
2015-11-22 21:11:23 -05:00
[ self addKeyCommandWithInput : @ "d" modifierFlags : UIKeyModifierShift action : @ selector ( backToDashboard : ) discoverabilityTitle : @ "Dashboard" ] ;
2012-11-05 15:12:42 -08:00
}
- ( void ) viewWillAppear : ( BOOL ) animated {
2014-09-18 11:25:51 -07:00
[ super viewWillAppear : animated ] ;
2020-05-26 14:13:46 -07:00
[ self updateTheme ] ;
2019-02-28 15:29:31 -08:00
[ self updateAutoscrollButtons ] ;
2015-12-07 16:09:49 -08:00
[ self updateTraverseBackground ] ;
2012-11-08 17:39:32 -08:00
[ self setNextPreviousButtons ] ;
2013-12-11 18:06:22 -08:00
[ self setTextButton ] ;
2020-04-22 19:53:17 -07:00
[ self updateStatusBarState ] ;
2019-02-27 13:33:38 -08:00
self . currentlyTogglingNavigationBar = NO ;
2020-06-20 21:31:21 -07:00
if ( self . standardInteractivePopGestureDelegate = = nil ) {
self . standardInteractivePopGestureDelegate = self . navigationController . interactivePopGestureRecognizer . delegate ;
}
2013-12-06 16:19:27 -08:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
BOOL swipeEnabled = [ [ userPreferences stringForKey : @ "story_detail_swipe_left_edge" ]
isEqualToString : @ "pop_to_story_list" ] ;;
2020-06-20 21:31:21 -07:00
self . navigationController . hidesBarsOnSwipe = self . allowFullscreen ;
2020-07-31 16:10:09 -07:00
[ self . navigationController . barHideOnSwipeGestureRecognizer addTarget : self action : @ selector ( barHideSwipe : ) ] ;
2013-12-06 16:19:27 -08:00
self . navigationController . interactivePopGestureRecognizer . enabled = swipeEnabled ;
2020-06-20 21:31:21 -07:00
self . navigationController . interactivePopGestureRecognizer . delegate = self ;
2015-11-28 22:07:38 -08:00
if ( self . isPhoneOrCompact ) {
2014-02-12 20:09:37 -08:00
if ( ! appDelegate . storiesCollection . isSocialView ) {
2012-11-13 13:07:36 -08:00
UIImage * titleImage ;
2014-02-12 20:09:37 -08:00
if ( appDelegate . storiesCollection . isSocialRiverView &&
[ appDelegate . storiesCollection . activeFolder isEqualToString : @ "river_global" ] ) {
2013-02-21 12:19:15 -08:00
titleImage = [ UIImage imageNamed : @ "ak-icon-global.png" ] ;
2014-02-12 20:09:37 -08:00
} else if ( appDelegate . storiesCollection . isSocialRiverView &&
[ appDelegate . storiesCollection . activeFolder isEqualToString : @ "river_blurblogs" ] ) {
2013-02-21 12:19:15 -08:00
titleImage = [ UIImage imageNamed : @ "ak-icon-blurblogs.png" ] ;
2014-02-12 20:09:37 -08:00
} else if ( appDelegate . storiesCollection . isRiverView &&
[ appDelegate . storiesCollection . activeFolder isEqualToString : @ "everything" ] ) {
2013-02-21 12:19:15 -08:00
titleImage = [ UIImage imageNamed : @ "ak-icon-allstories.png" ] ;
2017-11-05 22:07:43 -08:00
} else if ( appDelegate . storiesCollection . isRiverView &&
[ appDelegate . storiesCollection . activeFolder isEqualToString : @ "infrequent" ] ) {
titleImage = [ UIImage imageNamed : @ "ak-icon-allstories.png" ] ;
2014-05-20 15:29:16 -07:00
} else if ( appDelegate . storiesCollection . isSavedView &&
appDelegate . storiesCollection . activeSavedStoryTag ) {
titleImage = [ UIImage imageNamed : @ "tag.png" ] ;
2014-10-22 16:39:37 -07:00
} else if ( [ appDelegate . storiesCollection . activeFolder isEqualToString : @ "read_stories" ] ) {
2014-10-22 17:03:48 -07:00
titleImage = [ UIImage imageNamed : @ "g_icn_folder_read.png" ] ;
2020-05-27 21:26:44 -07:00
} else if ( [ appDelegate . storiesCollection . activeFolder isEqualToString : @ "saved_searches" ] ) {
2020-06-11 21:02:22 -07:00
titleImage = [ UIImage imageNamed : @ "g_icn_search.png" ] ;
2014-05-20 15:29:16 -07:00
} else if ( [ appDelegate . storiesCollection . activeFolder isEqualToString : @ "saved_stories" ] ) {
2013-03-07 10:55:23 -05:00
titleImage = [ UIImage imageNamed : @ "clock.png" ] ;
2014-02-12 20:09:37 -08:00
} else if ( appDelegate . storiesCollection . isRiverView ) {
2013-02-21 14:44:34 -08:00
titleImage = [ UIImage imageNamed : @ "g_icn_folder.png" ] ;
2012-11-13 13:07:36 -08:00
} else {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" ,
[ appDelegate . activeStory objectForKey : @ "story_feed_id" ] ] ;
2014-02-24 18:56:51 -08:00
titleImage = [ appDelegate getFavicon : feedIdStr ] ;
2012-11-13 13:07:36 -08:00
}
UIImageView * titleImageView = [ [ UIImageView alloc ] initWithImage : titleImage ] ;
2017-10-03 18:39:06 -07:00
UIImageView * titleImageViewWrapper = [ [ UIImageView alloc ] init ] ;
2014-02-12 20:09:37 -08:00
if ( appDelegate . storiesCollection . isRiverView ) {
2012-11-13 13:07:36 -08:00
titleImageView . frame = CGRectMake ( 0.0 , 2.0 , 22.0 , 22.0 ) ;
} else {
titleImageView . frame = CGRectMake ( 0.0 , 2.0 , 16.0 , 16.0 ) ;
}
titleImageView . hidden = YES ;
titleImageView . contentMode = UIViewContentModeScaleAspectFit ;
2017-10-03 18:39:06 -07:00
[ titleImageViewWrapper addSubview : titleImageView ] ;
[ titleImageViewWrapper setFrame : titleImageView . frame ] ;
2014-01-07 18:26:17 -08:00
if ( ! self . navigationItem . titleView ) {
2017-10-03 18:39:06 -07:00
self . navigationItem . titleView = titleImageViewWrapper ;
2014-01-07 18:26:17 -08:00
}
2012-11-13 13:07:36 -08:00
titleImageView . hidden = NO ;
} else {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" ,
2014-02-12 20:09:37 -08:00
[ appDelegate . storiesCollection . activeFeed objectForKey : @ "id" ] ] ;
2014-02-24 18:56:51 -08:00
UIImage * titleImage = [ appDelegate getFavicon : feedIdStr ] ;
2012-11-13 13:07:36 -08:00
titleImage = [ Utilities roundCorneredImage : titleImage radius : 6 ] ;
2017-10-03 18:39:06 -07:00
UIImageView * titleImageView = [ [ UIImageView alloc ] initWithFrame : CGRectZero ] ;
UIImageView * titleImageViewWrapper = [ [ UIImageView alloc ] init ] ;
titleImageView . frame = CGRectMake ( 0.0 , 0.0 , 28.0 , 28.0 ) ;
titleImageView . contentMode = UIViewContentModeScaleAspectFit ;
[ titleImageView setImage : titleImage ] ;
[ titleImageViewWrapper addSubview : titleImageView ] ;
[ titleImageViewWrapper setFrame : titleImageView . frame ] ;
self . navigationItem . titleView = titleImageViewWrapper ;
2012-11-13 13:07:36 -08:00
}
}
2012-12-18 17:29:23 -08:00
2019-02-28 15:29:31 -08:00
self . autoscrollView . alpha = 0 ;
2020-10-30 20:58:27 -07:00
// previousPage . view . hidden = YES ;
2013-09-05 16:34:39 -07:00
self . traverseView . alpha = 1 ;
2014-01-30 20:28:08 -08:00
self . isAnimatedIntoPlace = NO ;
2020-10-30 20:58:27 -07:00
// currentPage . view . hidden = NO ;
2014-01-08 13:38:18 -08:00
self . navigationItem . backBarButtonItem = [ [ UIBarButtonItem alloc ]
initWithTitle : @ " "
style : UIBarButtonItemStylePlain
target : nil action : nil ] ;
2015-09-22 18:20:48 -07:00
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2015-09-22 18:20:48 -07:00
[ self layoutForInterfaceOrientation : orientation ] ;
[ self adjustDragBar : orientation ] ;
2015-12-01 15:17:46 -08:00
[ self reorientPages ] ;
2012-11-05 15:12:42 -08:00
}
2012-11-05 17:16:10 -08:00
- ( void ) viewDidAppear : ( BOOL ) animated {
2014-09-18 11:25:51 -07:00
[ super viewDidAppear : animated ] ;
2012-11-05 17:16:10 -08:00
// set the subscribeButton flag
2016-12-06 16:03:40 -08:00
if ( appDelegate . isTryFeedView && ! self . isPhoneOrCompact &&
! [ [ appDelegate . storiesCollection . activeFeed objectForKey : @ "username" ] isKindOfClass : [ NSNull class ] ] &&
[ appDelegate . storiesCollection . activeFeed objectForKey : @ "username" ] ) {
2013-10-03 13:54:15 -07:00
self . subscribeButton . title = [ NSString stringWithFormat : @ "Follow %@" ,
2014-02-12 20:09:37 -08:00
[ appDelegate . storiesCollection . activeFeed objectForKey : @ "username" ] ] ;
2012-11-05 17:16:10 -08:00
self . navigationItem . leftBarButtonItem = self . subscribeButton ;
// self . subscribeButton . tintColor = UIColorFromRGB ( 0 x0a6720 ) ;
}
appDelegate . isTryFeedView = NO ;
2015-11-30 18:12:10 -08:00
[ self reorientPages ] ;
// [ self applyNewIndex : previousPage . pageIndex pageController : previousPage ] ;
2020-10-30 20:58:27 -07:00
// previousPage . view . hidden = NO ;
2019-05-16 13:58:03 -07:00
// [ self showAutoscrollBriefly : YES ] ;
2019-02-28 15:29:31 -08:00
2015-11-21 23:23:37 -05:00
[ self becomeFirstResponder ] ;
2013-09-25 10:47:35 -07:00
}
2015-09-23 13:02:25 -07:00
- ( void ) viewDidLayoutSubviews {
[ super viewDidLayoutSubviews ] ;
2015-10-05 11:45:33 -07:00
// [ self reorientPages ] ;
2015-09-23 13:02:25 -07:00
}
2014-02-21 16:06:49 -08:00
- ( void ) viewDidDisappear : ( BOOL ) animated {
2014-09-18 11:25:51 -07:00
[ super viewDidDisappear : animated ] ;
2014-02-21 16:06:49 -08:00
self . navigationItem . leftBarButtonItem = nil ;
2020-07-31 16:10:09 -07:00
[ self . navigationController . barHideOnSwipeGestureRecognizer removeTarget : self action : @ selector ( barHideSwipe : ) ] ;
2014-02-21 16:06:49 -08:00
}
2013-09-25 10:47:35 -07:00
- ( void ) viewWillDisappear : ( BOOL ) animated {
2014-09-18 11:25:51 -07:00
[ super viewWillDisappear : animated ] ;
2020-10-30 20:58:27 -07:00
// previousPage . view . hidden = YES ;
2020-06-20 21:31:21 -07:00
self . navigationController . hidesBarsOnSwipe = NO ;
2013-10-11 17:46:09 -07:00
self . navigationController . interactivePopGestureRecognizer . enabled = YES ;
2020-06-20 21:31:21 -07:00
self . navigationController . interactivePopGestureRecognizer . delegate = self . standardInteractivePopGestureDelegate ;
2020-11-25 21:39:11 -08:00
[ self . navigationController setNavigationBarHidden : NO animated : YES ] ;
2019-02-28 15:29:31 -08:00
self . autoscrollActive = NO ;
2012-11-05 17:16:10 -08:00
}
2015-11-22 21:11:23 -05:00
- ( BOOL ) becomeFirstResponder {
// delegate to current page
2020-10-30 20:58:27 -07:00
return [ self . currentStoryController becomeFirstResponder ] ;
2015-11-22 21:11:23 -05:00
}
2012-11-07 17:54:16 -08:00
- ( void ) transitionFromFeedDetail {
2020-11-24 21:34:45 -08:00
if ( appDelegate . detailViewController . storyTitlesOnLeft ) {
2020-08-29 21:19:32 -07:00
[ appDelegate . feedsNavigationController
popToViewController : [ appDelegate . feedsNavigationController . viewControllers
2016-10-05 21:32:22 -07:00
objectAtIndex : 0 ]
animated : YES ] ;
[ appDelegate hideStoryDetailView ] ;
} else {
[ appDelegate . masterContainerViewController transitionFromFeedDetail ] ;
}
2012-11-07 17:54:16 -08:00
}
2015-09-22 13:25:18 -07:00
- ( void ) viewWillTransitionToSize : ( CGSize ) size withTransitionCoordinator : ( id < UIViewControllerTransitionCoordinator > ) coordinator {
2015-09-22 16:34:24 -07:00
[ super viewWillTransitionToSize : size withTransitionCoordinator : coordinator ] ;
2017-11-06 21:13:07 -08:00
inRotation = YES ;
2015-09-22 13:25:18 -07:00
[ coordinator animateAlongsideTransition : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
2017-11-06 21:13:07 -08:00
// NSLog ( @ "---> Story page control is re-orienting: %@ / %@" , NSStringFromCGSize ( self . scrollView . bounds . size ) , NSStringFromCGSize ( size ) ) ;
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2020-09-22 17:28:14 -07:00
self -> _orientation = orientation ;
2015-09-22 13:25:18 -07:00
[ self layoutForInterfaceOrientation : orientation ] ;
[ self adjustDragBar : orientation ] ;
[ self reorientPages ] ;
} completion : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
2017-11-06 21:13:07 -08:00
// NSLog ( @ "---> Story page control did re-orient: %@ / %@" , NSStringFromCGSize ( self . scrollView . bounds . size ) , NSStringFromCGSize ( size ) ) ;
2020-08-27 15:08:46 -07:00
self -> inRotation = NO ;
2020-04-22 19:31:08 -07:00
[ self updateStatusBarState ] ;
2017-11-06 21:13:07 -08:00
2016-06-16 17:10:04 -07:00
[ self . view setNeedsLayout ] ;
[ self . view layoutIfNeeded ] ;
2016-11-01 15:10:56 -07:00
// This causes the story to reload on rotation ( or when going to the background ) , but doesn ' t seem necessary ?
// [ self refreshPages ] ;
2015-09-22 13:25:18 -07:00
} ] ;
}
2013-03-04 17:15:50 -08:00
- ( void ) layoutForInterfaceOrientation : ( UIInterfaceOrientation ) interfaceOrientation {
2020-03-29 16:21:00 -07:00
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad &&
2014-02-28 17:52:07 -08:00
// appDelegate . masterContainerViewController . originalViewIsVisible ) {
// return ;
// }
2014-09-22 12:35:38 -07:00
// NSLog ( @ "layout for stories: %@" , NSStringFromCGRect ( self . view . frame ) ) ;
2020-10-30 20:58:27 -07:00
// if ( interfaceOrientation ! = _orientation ) {
// _orientation = interfaceOrientation ;
// if ( self . currentStoryController . pageIndex = = 0 ) {
// previousPage . view . hidden = YES ;
// }
// }
2012-11-07 17:54:16 -08:00
}
2015-12-01 15:17:46 -08:00
- ( void ) viewWillLayoutSubviews {
[ super viewWillLayoutSubviews ] ;
2020-07-31 16:10:09 -07:00
if ( self . isNavigationBarHidden && ! self . shouldHideStatusBar ) {
self . scrollViewTopConstraint . constant = self . statusBarHeight ;
} else {
self . scrollViewTopConstraint . constant = 0 ;
}
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2015-12-01 15:17:46 -08:00
[ self layoutForInterfaceOrientation : orientation ] ;
[ self adjustDragBar : orientation ] ;
}
2020-07-31 16:10:09 -07:00
- ( BOOL ) shouldHideStatusBar {
2020-04-22 19:31:08 -07:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
2020-07-31 16:10:09 -07:00
return [ preferences boolForKey : @ "story_hide_status_bar" ] ;
2020-04-22 19:31:08 -07:00
}
2020-07-31 16:10:09 -07:00
- ( BOOL ) isNavigationBarHidden {
return self . navigationController . navigationBarHidden ;
}
- ( void ) updateStatusBarState {
BOOL isNavBarHidden = self . isNavigationBarHidden ;
2020-04-22 19:31:08 -07:00
2020-07-31 16:10:09 -07:00
self . statusBarBackgroundView . hidden = self . shouldHideStatusBar || ! isNavBarHidden || ! appDelegate . isPortrait ;
}
- ( BOOL ) prefersStatusBarHidden {
2020-04-22 19:31:08 -07:00
[ self updateStatusBarState ] ;
2020-07-31 16:10:09 -07:00
return self . shouldHideStatusBar && self . isNavigationBarHidden ;
iOS: #1137 (full screen reading)
Added a "Tap story" preference with "Toggle full screen" and "Do nothing" options; toggling is the default. This is only available on iPhone. When active, a single tap in a story, not on a link, image, movie, or button, will hide or show the status and navigation bars. On iPhones with a notch (iPhone X, XS, etc), the feed bar at the top is also hidden, so the story can scroll under the notch, using every bit of the screen.
2018-10-31 20:05:11 -07:00
}
2020-06-20 21:31:21 -07:00
- ( BOOL ) allowFullscreen {
2020-09-22 17:28:14 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] ! = UIUserInterfaceIdiomPhone || self . presentedViewController ! = nil ) {
2020-06-20 21:31:21 -07:00
return NO ;
}
2019-02-27 13:33:38 -08:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
2019-03-04 20:07:42 -08:00
return ( [ preferences boolForKey : @ "story_full_screen" ] || self . autoscrollAvailable ) && ! self . forceNavigationBarShown ;
2019-02-27 13:33:38 -08:00
}
2019-01-16 19:15:07 -08:00
- ( void ) setNavigationBarHidden : ( BOOL ) hide {
2019-01-24 20:04:00 -08:00
[ self setNavigationBarHidden : hide alsoTraverse : NO ] ;
}
- ( void ) setNavigationBarHidden : ( BOOL ) hide alsoTraverse : ( BOOL ) alsoTraverse {
2019-05-16 19:31:24 -07:00
if ( self . navigationController = = nil || self . navigationController . navigationBarHidden = = hide || self . currentlyTogglingNavigationBar ) {
2019-01-16 19:15:07 -08:00
return ;
}
self . currentlyTogglingNavigationBar = YES ;
2020-07-31 16:10:09 -07:00
self . wasNavigationBarHidden = hide ;
2019-01-16 19:15:07 -08:00
[ self . navigationController setNavigationBarHidden : hide animated : YES ] ;
2020-10-30 20:58:27 -07:00
CGPoint oldOffset = self . currentStoryController . webView . scrollView . contentOffset ;
2019-01-16 19:15:07 -08:00
CGFloat navHeight = self . navigationController . navigationBar . bounds . size . height ;
CGFloat statusAdjustment = 20.0 ;
2020-09-25 20:31:01 -07:00
// The top inset is zero when the status bar is hidden , so using the bottom one to confirm .
if ( self . view . safeAreaInsets . top > 0.0 || self . view . safeAreaInsets . bottom > 0.0 ) {
statusAdjustment = 0.0 ;
2019-01-16 19:15:07 -08:00
}
if ( oldOffset . y < 0.0 ) {
oldOffset . y = 0.0 ;
}
CGFloat sign = hide ? -1.0 : 1.0 ;
CGFloat absoluteAdjustment = navHeight + statusAdjustment ;
CGFloat totalAdjustment = sign * absoluteAdjustment ;
CGPoint newOffset = CGPointMake ( oldOffset . x , oldOffset . y + totalAdjustment ) ;
2020-10-30 20:58:27 -07:00
BOOL singlePage = self . currentStoryController . isSinglePage ;
2019-01-16 19:15:07 -08:00
2019-01-24 20:04:00 -08:00
if ( alsoTraverse ) {
self . traversePinned = YES ;
self . traverseFloating = NO ;
if ( ! hide ) {
int safeBottomMargin = 0 ;
2019-04-16 20:24:42 -07:00
if ( self . isPhoneOrCompact ) {
2020-09-25 20:31:01 -07:00
safeBottomMargin = -1 * self . view . safeAreaInsets . bottom / 2 ;
2019-01-24 20:04:00 -08:00
}
self . traverseBottomConstraint . constant = safeBottomMargin ;
[ self . view layoutIfNeeded ] ;
}
}
2019-01-16 19:15:07 -08:00
[ UIView animateWithDuration : 0.2 animations : ^ {
2019-02-27 13:33:38 -08:00
if ( ! self . isHorizontal ) {
[ self reorientPages ] ;
}
2019-04-16 20:24:42 -07:00
if ( ! singlePage ) {
2020-10-30 20:58:27 -07:00
self . currentStoryController . webView . scrollView . contentOffset = newOffset ;
2019-04-16 20:24:42 -07:00
}
2019-01-24 20:04:00 -08:00
if ( alsoTraverse ) {
[ self . view layoutIfNeeded ] ;
self . traverseView . alpha = hide ? 0 : 1 ;
2019-05-16 13:58:03 -07:00
if ( hide ) {
[ self hideAutoscrollImmediately ] ;
}
2019-01-24 20:04:00 -08:00
}
2019-01-16 19:15:07 -08:00
} ] ;
if ( ! hide ) {
[ self resizeScrollView ] ;
}
[ UIView animateWithDuration : 0.2 animations : ^ {
[ self setNeedsStatusBarAppearanceUpdate ] ;
} completion : ^ ( BOOL finished ) {
self . currentlyTogglingNavigationBar = NO ;
2020-04-22 19:31:08 -07:00
[ self updateStatusBarState ] ;
2019-01-16 19:15:07 -08:00
} ] ;
}
2019-04-24 13:02:04 -07:00
- ( BOOL ) gestureRecognizerShouldBegin : ( UIGestureRecognizer * ) gestureRecognizer {
return YES ;
}
2019-05-28 19:40:15 -07:00
- ( BOOL ) gestureRecognizer : ( UIGestureRecognizer * ) gestureRecognizer shouldBeRequiredToFailByGestureRecognizer : ( UIGestureRecognizer * ) otherGestureRecognizer {
return ! [ otherGestureRecognizer isKindOfClass : [ UIScreenEdgePanGestureRecognizer class ] ] ;
}
2013-09-26 19:26:10 -07:00
- ( void ) adjustDragBar : ( UIInterfaceOrientation ) orientation {
2015-09-23 13:02:25 -07:00
// CGRect scrollViewFrame = self . scrollView . frame ;
// CGRect traverseViewFrame = self . traverseView . frame ;
2013-09-26 19:26:10 -07:00
2015-11-28 22:07:38 -08:00
if ( self . isPhoneOrCompact ||
2013-09-26 19:26:10 -07:00
UIInterfaceOrientationIsLandscape ( orientation ) ) {
2017-11-06 21:13:07 -08:00
// scrollViewFrame . size . height = self . scrollView . bounds . size . height ;
2015-09-23 13:02:25 -07:00
// self . bottomSize . hidden = YES ;
[ self . bottomSizeHeightConstraint setConstant : 0 ] ;
2017-11-06 20:09:31 -08:00
[ self . scrollBottomConstraint setConstant : 0 ] ;
2016-02-18 12:15:09 -08:00
[ bottomSize setHidden : YES ] ;
2013-09-26 19:26:10 -07:00
} else {
2017-11-06 21:13:07 -08:00
// scrollViewFrame . size . height = self . scrollView . bounds . size . height - 12 ;
2015-09-23 13:02:25 -07:00
// self . bottomSize . hidden = NO ;
[ self . bottomSizeHeightConstraint setConstant : 12 ] ;
2017-11-06 20:09:31 -08:00
[ self . scrollBottomConstraint setConstant : -12 ] ;
2016-02-18 12:15:09 -08:00
[ bottomSize setHidden : NO ] ;
2013-09-26 19:26:10 -07:00
}
2015-09-28 20:01:17 -07:00
[ self . view layoutIfNeeded ] ;
2015-09-22 18:20:48 -07:00
// self . scrollView . frame = scrollViewFrame ;
// traverseViewFrame . origin . y = scrollViewFrame . size . height - traverseViewFrame . size . height ;
// self . traverseView . frame = traverseViewFrame ;
2013-09-26 19:26:10 -07:00
}
2013-10-08 13:57:15 -07:00
- ( void ) highlightButton : ( UIButton * ) b {
2013-10-10 13:00:35 -07:00
if ( ! [ b isKindOfClass : [ UIButton class ] ] ) return ;
2013-10-08 13:57:15 -07:00
[ b setHighlighted : YES ] ;
}
- ( void ) unhighlightButton : ( UIButton * ) b {
2013-10-10 13:00:35 -07:00
if ( ! [ b isKindOfClass : [ UIButton class ] ] ) return ;
2013-10-08 13:57:15 -07:00
[ b setHighlighted : NO ] ;
}
- ( IBAction ) beginTouchDown : ( UIButton * ) sender {
[ self performSelector : @ selector ( highlightButton : ) withObject : sender afterDelay : 0.0 ] ;
}
- ( IBAction ) endTouchDown : ( UIButton * ) sender {
if ( ! sender ) return ;
[ self performSelector : @ selector ( unhighlightButton : ) withObject : sender afterDelay : 0.2 ] ;
}
2018-08-30 16:33:42 -07:00
- ( BOOL ) isHorizontal {
return [ [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "scroll_stories_horizontally" ] boolValue ] ;
}
2020-07-31 16:10:09 -07:00
- ( void ) barHideSwipe : ( UIPanGestureRecognizer * ) recognizer {
BOOL isBarHidden = self . isNavigationBarHidden ;
if ( recognizer . state = = UIGestureRecognizerStateEnded && isBarHidden ! = self . wasNavigationBarHidden ) {
self . wasNavigationBarHidden = isBarHidden ;
2020-09-25 20:31:01 -07:00
if ( ! self . shouldHideStatusBar ) {
2020-10-30 20:58:27 -07:00
[ self . currentStoryController drawFeedGradient ] ;
2020-07-31 16:10:09 -07:00
}
if ( ! self . isHorizontal ) {
[ self reorientPages ] ;
}
}
}
2020-10-30 20:58:27 -07:00
// These methods are implemented in the Swift subclass , but declared here so that this class can use them . These implementations should never be called ; if they are , that indicates the Swift implementation is missing , has the wrong name , or missing the @ objc attribute .
2014-01-07 18:26:17 -08:00
2020-10-30 20:58:27 -07:00
- ( StoryDetailViewController * ) currentStoryController {
@ throw [ NSException exceptionWithName : @ "Missing currentStoryController implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
return nil ;
}
2012-11-09 09:31:26 -08:00
2020-10-30 20:58:27 -07:00
- ( NSArray < StoryDetailViewController * > * ) storyControllers {
@ throw [ NSException exceptionWithName : @ "Missing storyControllers implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
return @ [ ] ;
}
- ( void ) updateStoryControllers : ( void ( ^ ) ( StoryDetailViewController * ) ) handler {
@ throw [ NSException exceptionWithName : @ "Missing -updateStoryControllers: implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
}
2012-12-11 12:01:49 -08:00
2020-10-30 20:58:27 -07:00
- ( void ) resetOtherStoryControllers {
@ throw [ NSException exceptionWithName : @ "Missing -resetOtherStoryControllers implementation" reason : @ "This is implemented in the Swift subclass, so should never reach here." userInfo : nil ] ;
2013-10-11 17:46:09 -07:00
}
- ( void ) hidePages {
2020-10-30 20:58:27 -07:00
[ self resetOtherStoryControllers ] ;
2012-11-07 17:54:16 -08:00
}
2012-11-13 12:28:16 -08:00
- ( void ) refreshPages {
2020-10-30 20:58:27 -07:00
NSInteger pageIndex = self . currentStoryController . pageIndex ;
2012-11-13 12:28:16 -08:00
[ self resizeScrollView ] ;
[ appDelegate adjustStoryDetailWebView ] ;
2020-10-30 20:58:27 -07:00
[ self resetOtherStoryControllers ] ;
2012-11-13 12:28:16 -08:00
[ self changePage : pageIndex animated : NO ] ;
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
2015-10-28 21:50:23 -07:00
[ self . notifier hide ] ;
2012-11-13 12:28:16 -08:00
// self . scrollView . contentOffset = CGPointMake ( self . scrollView . frame . size . width * currentPage . pageIndex , 0 ) ;
}
2015-09-22 13:25:18 -07:00
- ( void ) reorientPages {
2020-10-30 20:58:27 -07:00
# warning obsolete
// [ self applyNewIndex : self . currentStoryController . pageIndex pageController : self . currentStoryController supressRedraw : YES ] ;
2014-12-03 15:35:37 -08:00
2020-10-30 20:58:27 -07:00
// [ self applyNewIndex : currentPage . pageIndex -1 pageController : previousPage supressRedraw : YES ] ;
// [ self applyNewIndex : currentPage . pageIndex + 1 pageController : nextPage supressRedraw : YES ] ;
// [ self applyNewIndex : currentPage . pageIndex pageController : currentPage supressRedraw : YES ] ;
//
// NSInteger currentIndex = currentPage . pageIndex ;
// [ self resizeScrollView ] ; // Will change currentIndex , so preserve
//
// // Scroll back to preserved index
// CGRect frame = self . scrollView . bounds ;
// if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
// frame = self . scrollView . bounds ;
// }
//
// if ( self . isHorizontal ) {
// frame . origin . x = frame . size . width * currentIndex ;
// frame . origin . y = 0 ;
//
// // if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
// // frame . origin . y - = self . view . safeAreaInsets . bottom ;
// // }
// } else {
// frame . origin . x = 0 ;
// frame . origin . y = ( frame . size . height * currentIndex ) - self . view . safeAreaInsets . bottom ;
// }
//
// [ self . scrollView scrollRectToVisible : frame animated : NO ] ;
2015-12-01 16:51:18 -08:00
// NSLog ( @ "---> Scrolling to story at: %@ %d-%d" , NSStringFromCGRect ( frame ) , currentPage . pageIndex , currentIndex ) ;
2014-11-30 21:24:42 -05:00
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
2015-12-01 15:17:46 -08:00
[ self hideNotifier ] ;
2014-11-30 21:24:42 -05:00
}
2012-12-07 17:18:31 -08:00
- ( void ) refreshHeaders {
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController setActiveStoryAtIndex : [ self . appDelegate . storiesCollection indexOfStoryId : storyController . activeStoryId ] ] ;
[ storyController refreshHeader ] ;
[ storyController refreshSideOptions ] ;
} ] ;
2012-12-07 17:18:31 -08:00
}
2015-12-01 15:17:46 -08:00
2012-11-06 17:26:08 -08:00
- ( void ) resizeScrollView {
2020-10-30 20:58:27 -07:00
# warning obsolete
// NSInteger storyCount = appDelegate . storiesCollection . storyLocationsCount ;
// if ( storyCount = = 0 ) {
// storyCount = 1 ;
// }
//
// if ( self . isHorizontal ) {
// self . scrollView . contentSize = CGSizeMake ( self . scrollView . bounds . size . width
// * storyCount ,
// self . scrollView . bounds . size . height ) ;
// } else {
// self . scrollView . contentSize = CGSizeMake ( self . scrollView . bounds . size . width ,
// self . scrollView . bounds . size . height
// * storyCount ) ;
// }
2012-11-06 17:26:08 -08:00
}
2012-11-07 17:54:16 -08:00
- ( void ) touchesMoved : ( NSSet * ) touches withEvent : ( UIEvent * ) event {
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2012-11-07 17:54:16 -08:00
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact &&
2013-10-03 13:54:15 -07:00
UIInterfaceOrientationIsPortrait ( orientation ) ) {
2012-11-07 17:54:16 -08:00
UITouch * theTouch = [ touches anyObject ] ;
2013-12-12 18:41:39 -08:00
CGPoint tappedPt = [ theTouch locationInView : self . view ] ;
2020-11-24 21:34:45 -08:00
NSInteger fudge = appDelegate . detailViewController . storyTitlesOnLeft ? -30 : -20 ;
2013-12-12 18:41:39 -08:00
BOOL inside = CGRectContainsPoint ( CGRectInset ( self . bottomSize . frame , 0 , fudge ) , tappedPt ) ;
BOOL attached = self . inTouchMove ;
if ( theTouch . view = = self . bottomSize || inside || attached ) {
2012-11-07 17:54:16 -08:00
self . inTouchMove = YES ;
2013-09-26 19:26:10 -07:00
CGPoint touchLocation = [ theTouch locationInView : self . view ] ;
CGFloat y = touchLocation . y ;
[ appDelegate . masterContainerViewController dragStoryToolbar : y ] ;
2012-11-07 17:54:16 -08:00
}
}
}
- ( void ) touchesEnded : ( NSSet * ) touches withEvent : ( UIEvent * ) event {
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2012-11-07 17:54:16 -08:00
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact &&
2013-10-03 13:54:15 -07:00
UIInterfaceOrientationIsPortrait ( orientation ) ) {
2013-12-12 18:41:39 -08:00
if ( self . inTouchMove ) {
2012-11-07 17:54:16 -08:00
self . inTouchMove = NO ;
[ appDelegate . masterContainerViewController adjustFeedDetailScreenForStoryTitles ] ;
}
}
}
2015-11-28 22:07:38 -08:00
- ( BOOL ) isPhoneOrCompact {
2020-03-29 16:21:00 -07:00
return [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone || appDelegate . isCompactWidth ;
2015-11-28 22:07:38 -08:00
}
2019-02-28 15:29:31 -08:00
- ( void ) updateAutoscrollButtons {
self . autoscrollBackgroundImageView . image = [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_background.png" ] ] ;
[ self . autoscrollDisableButton setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "autoscroll_off.png" ] ] forState : UIControlStateNormal ] ;
if ( self . autoscrollActive ) {
[ self . autoscrollPauseResumeButton setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "autoscroll_pause.png" ] ] forState : UIControlStateNormal ] ;
} else {
[ self . autoscrollPauseResumeButton setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "autoscroll_resume.png" ] ] forState : UIControlStateNormal ] ;
}
[ self . autoscrollSlowerButton setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "autoscroll_slower.png" ] ] forState : UIControlStateNormal ] ;
[ self . autoscrollFasterButton setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "autoscroll_faster.png" ] ] forState : UIControlStateNormal ] ;
}
2015-12-07 16:09:49 -08:00
- ( void ) updateTraverseBackground {
self . textStorySendBackgroundImageView . image = [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_background.png" ] ] ;
self . prevNextBackgroundImageView . image = [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_background.png" ] ] ;
self . dragBarImageView . image = [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "drag_icon.png" ] ] ;
self . bottomSize . backgroundColor = UIColorFromRGB ( NEWSBLUR_WHITE _COLOR ) ;
}
- ( void ) updateTheme {
[ super updateTheme ] ;
2019-10-22 21:14:15 -07:00
self . navigationController . navigationBar . tintColor = [ UINavigationBar appearance ] . tintColor ;
2020-02-20 20:32:49 -08:00
self . navigationController . navigationBar . barTintColor = UIColorFromLightSepiaMediumDarkRGB ( 0 xE3E6E0 , 0 xFFFFC5 , 0 x222222 , 0 x111111 ) ;
2019-10-22 21:14:15 -07:00
self . navigationController . navigationBar . backgroundColor = [ UINavigationBar appearance ] . backgroundColor ;
2020-02-20 20:32:49 -08:00
self . view . backgroundColor = UIColorFromLightDarkRGB ( 0 xe0e0e0 , 0 x111111 ) ;
2019-10-22 21:14:15 -07:00
2019-02-28 15:29:31 -08:00
[ self updateAutoscrollButtons ] ;
2015-12-07 16:09:49 -08:00
[ self updateTraverseBackground ] ;
[ self setNextPreviousButtons ] ;
[ self setTextButton ] ;
2018-10-22 15:14:12 -07:00
[ self updateStoriesTheme ] ;
2020-04-22 19:31:08 -07:00
[ self updateStatusBarTheme ] ;
2015-12-07 16:09:49 -08:00
}
2015-11-21 23:23:37 -05:00
// allow keyboard comands
- ( BOOL ) canBecomeFirstResponder {
return YES ;
}
2019-03-22 20:55:22 -07:00
# pragma mark -
# pragma mark State Restoration
- ( void ) encodeRestorableStateWithCoder : ( NSCoder * ) coder {
[ super encodeRestorableStateWithCoder : coder ] ;
2020-10-30 20:58:27 -07:00
[ coder encodeObject : self . currentStoryController . activeStoryId forKey : @ "current_story_id" ] ;
2019-03-22 20:55:22 -07:00
[ appDelegate . storiesCollection toggleStoryUnread ] ;
self . temporarilyMarkedUnread = YES ;
}
- ( void ) decodeRestorableStateWithCoder : ( NSCoder * ) coder {
[ super decodeRestorableStateWithCoder : coder ] ;
self . restoringStoryId = [ coder decodeObjectOfClass : [ NSString class ] forKey : @ "current_story_id" ] ;
}
- ( void ) restorePage {
if ( self . restoringStoryId . length > 0 ) {
NSInteger pageIndex = [ appDelegate . storiesCollection indexOfStoryId : self . restoringStoryId ] ;
2019-08-23 20:14:22 -07:00
if ( pageIndex >= 0 ) {
2019-03-22 20:55:22 -07:00
[ self changePage : pageIndex animated : NO ] ;
2020-03-29 16:21:00 -07:00
} else if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
2020-03-24 17:05:22 -07:00
// If the story can ' t be found , don ' t show anything ; uncomment this to instead show the first unread story :
// [ self doNextUnreadStory : nil ] ;
2019-08-23 20:14:22 -07:00
} else {
[ appDelegate hideStoryDetailView ] ;
2019-03-22 20:55:22 -07:00
}
self . restoringStoryId = nil ;
}
}
2012-11-07 17:54:16 -08:00
# pragma mark -
# pragma mark Side scroll view
2020-10-30 20:58:27 -07:00
- ( NSInteger ) storiesCount {
return appDelegate . storiesCollection . activeFeedStoryLocations . count ;
}
- ( BOOL ) pageIndexIsValid : ( NSInteger ) pageIndex {
return pageIndex >= 0 && pageIndex < self . storiesCount ;
}
2013-10-03 13:54:15 -07:00
- ( void ) applyNewIndex : ( NSInteger ) newIndex
pageController : ( StoryDetailViewController * ) pageController {
2014-11-30 21:24:42 -05:00
[ self applyNewIndex : newIndex pageController : pageController supressRedraw : NO ] ;
}
- ( void ) applyNewIndex : ( NSInteger ) newIndex
pageController : ( StoryDetailViewController * ) pageController
supressRedraw : ( BOOL ) suppressRedraw {
2020-10-30 20:58:27 -07:00
BOOL outOfBounds = ! [ self pageIndexIsValid : newIndex ] ;
# warning obsolete
// if ( ! outOfBounds ) {
// CGRect pageFrame = pageController . view . bounds ;
// if ( self . isHorizontal ) {
// pageFrame . origin . y = 0 ;
// pageFrame . origin . x = CGRectGetWidth ( self . scrollView . bounds ) * newIndex ;
// } else {
// pageFrame . origin . y = CGRectGetHeight ( self . scrollView . bounds ) * newIndex ;
// pageFrame . origin . x = 0 ;
// }
// pageFrame . size . height = CGRectGetHeight ( self . scrollView . bounds ) ;
// pageFrame . size . width = CGRectGetWidth ( self . scrollView . bounds ) ;
//
// if ( self . currentlyTogglingNavigationBar && ! self . isNavigationBarHidden ) {
// pageFrame . size . height - = 20.0 ;
// }
//
// pageController . view . hidden = NO ;
// pageController . view . frame = pageFrame ;
// } else {
// // NSLog ( @ "Out of bounds: was %@, now %@" , @ ( pageController . pageIndex ) , @ ( newIndex ) ) ;
// CGRect pageFrame = pageController . view . bounds ;
// if ( self . isHorizontal ) {
// pageFrame . origin . x = CGRectGetWidth ( self . scrollView . bounds ) * newIndex ;
// pageFrame . origin . y = CGRectGetHeight ( self . scrollView . bounds ) ;
// } else {
// pageFrame . origin . x = 0 ;
// pageFrame . origin . y = CGRectGetHeight ( self . scrollView . bounds ) * newIndex ;
// }
// pageFrame . size . height = CGRectGetHeight ( self . scrollView . bounds ) ;
// pageFrame . size . width = CGRectGetWidth ( self . scrollView . bounds ) ;
// pageController . view . hidden = YES ;
// pageController . view . frame = pageFrame ;
// }
2018-08-30 16:33:42 -07:00
// NSLog ( @ "---> Story page control orient page: %@ (%@-%@)" , NSStringFromCGRect ( self . scrollView . bounds ) , @ ( pageController . pageIndex ) , suppressRedraw ? @ "supress" : @ "redraw" ) ;
2015-11-30 18:12:10 -08:00
2014-11-30 21:24:42 -05:00
if ( suppressRedraw ) return ;
2020-10-30 20:58:27 -07:00
// Make sure the view has been loaded .
[ pageController view ] ;
2018-09-06 11:31:17 -07:00
// NSInteger wasIndex = pageController . pageIndex ;
2012-11-05 15:12:42 -08:00
pageController . pageIndex = newIndex ;
2020-10-30 20:58:27 -07:00
if ( pageController = = self . currentStoryController ) {
[ self resetOtherStoryControllers ] ;
}
2020-11-24 21:34:45 -08:00
[ self . splitViewController showColumn : UISplitViewControllerColumnSecondary ] ;
2020-10-30 20:58:27 -07:00
// NSLog ( @ "Applied Index to %@: Was %ld, now %ld (%ld/%ld/%ld) [%lu stories - %d] %@" , pageController , ( long ) wasIndex , ( long ) newIndex , ( long ) previousPage . pageIndex , ( long ) currentPage . pageIndex , ( long ) nextPage . pageIndex , ( unsigned long ) self . storiesCount , outOfBounds , NSStringFromCGRect ( self . scrollView . frame ) ) ;
if ( newIndex > 0 && newIndex >= self . storiesCount ) {
2012-12-06 15:30:16 -08:00
pageController . pageIndex = -2 ;
2017-04-03 16:07:01 -07:00
if ( appDelegate . storiesCollection . feedPage < 100 &&
! appDelegate . feedDetailViewController . pageFinished &&
! appDelegate . feedDetailViewController . pageFetching ) {
[ appDelegate . feedDetailViewController fetchNextPage : ^ ( ) {
2020-10-30 20:58:27 -07:00
// NSLog ( @ "Fetched next page, %@ stories" , @ ( self . storiesCount ) ) ;
2012-11-05 18:23:45 -08:00
[ self applyNewIndex : newIndex pageController : pageController ] ;
} ] ;
2017-04-03 16:07:01 -07:00
} else if ( ! appDelegate . feedDetailViewController . pageFinished &&
! appDelegate . feedDetailViewController . pageFetching ) {
2020-08-29 21:19:32 -07:00
[ appDelegate . feedsNavigationController
popToViewController : [ appDelegate . feedsNavigationController . viewControllers
2012-12-06 15:30:16 -08:00
objectAtIndex : 0 ]
animated : YES ] ;
[ appDelegate hideStoryDetailView ] ;
2012-11-05 18:23:45 -08:00
}
2012-11-14 17:31:52 -08:00
} else if ( ! outOfBounds ) {
2014-02-12 20:09:37 -08:00
NSInteger location = [ appDelegate . storiesCollection indexFromLocation : pageController . pageIndex ] ;
2012-11-06 13:45:15 -08:00
[ pageController setActiveStoryAtIndex : location ] ;
2012-11-14 17:31:52 -08:00
[ pageController clearStory ] ;
2012-11-19 19:15:05 -08:00
if ( self . isDraggingScrollview ||
2012-11-26 16:47:20 -08:00
self . scrollingToPage < 0 ||
2013-09-25 17:43:00 -07:00
ABS ( newIndex - self . scrollingToPage ) <= 1 ) {
2015-10-02 16:04:49 -07:00
[ pageController drawFeedGradient ] ;
2015-10-06 18:52:58 -07:00
NSString * originalStoryId = pageController . activeStoryId ;
__block StoryDetailViewController * blockPageController = pageController ;
2015-10-02 16:04:49 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _HIGH , 0 ul ) , ^ {
2015-10-06 18:52:58 -07:00
if ( blockPageController . activeStoryId && ! [ blockPageController . activeStoryId isEqualToString : originalStoryId ] ) {
2018-08-30 16:33:42 -07:00
// NSLog ( @ "Stale story, already drawn. Was: %@, Now: %@" , originalStoryId , blockPageController . activeStoryId ) ;
2015-10-06 18:52:58 -07:00
return ;
}
2016-04-14 20:28:16 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
[ blockPageController initStory ] ;
[ blockPageController drawStory ] ;
[ blockPageController showTextOrStoryView ] ;
} ) ;
2015-10-02 16:04:49 -07:00
} ) ;
2012-11-14 17:31:52 -08:00
} else {
2015-03-10 18:58:23 -07:00
// [ pageController clearStory ] ;
2013-01-07 16:34:59 -08:00
// NSLog ( @ "Skipping drawing %d (waiting for %d)" , newIndex , self . scrollingToPage ) ;
2012-11-14 17:31:52 -08:00
}
} else if ( outOfBounds ) {
2020-10-30 20:58:27 -07:00
[ pageController hideStory ] ; // clearStory ] ;
2020-11-24 21:34:45 -08:00
// TODO : might want to check if overlay display , or something , to avoid doing this on compact layout
[ self . splitViewController showColumn : UISplitViewControllerColumnPrimary ] ;
2012-11-05 18:23:45 -08:00
}
2012-11-05 17:16:10 -08:00
2014-12-03 15:35:37 -08:00
if ( ! suppressRedraw ) {
[ self resizeScrollView ] ;
}
2013-05-29 13:36:39 -07:00
[ self setTextButton ] ;
2012-11-05 17:16:10 -08:00
[ self . loadingIndicator stopAnimating ] ;
2013-04-23 11:52:34 -07:00
self . circularProgressView . hidden = NO ;
2012-11-05 15:12:42 -08:00
}
2012-11-14 17:31:52 -08:00
- ( void ) scrollViewDidScroll : ( UIScrollView * ) sender {
2020-10-30 20:58:27 -07:00
# warning somewhat obsolete ; need to extract out the traverse stuff
// // [ sender setContentOffset : CGPointMake ( sender . contentOffset . x , 0 ) ] ;
// if ( inRotation ) return ;
// CGSize size = self . scrollView . frame . size ;
// CGPoint offset = self . scrollView . contentOffset ;
// CGFloat pageAmount = self . isHorizontal ? size . width : size . height ;
// float fractionalPage = ( self . isHorizontal ? offset . x : offset . y ) / pageAmount ;
//
// NSInteger lowerNumber = floor ( fractionalPage ) ;
// NSInteger upperNumber = lowerNumber + 1 ;
// NSInteger previousNumber = lowerNumber - 1 ;
//
// NSInteger storyCount = self . storiesCount ;
// if ( storyCount = = 0 || lowerNumber > storyCount ) return ;
//
// // NSLog ( @ "Did Scroll: %@ = %@ (%@/%@/%@)" , @ ( fractionalPage ) , @ ( lowerNumber ) , @ ( previousPage . pageIndex ) , @ ( currentPage . pageIndex ) , @ ( nextPage . pageIndex ) ) ;
// if ( lowerNumber = = currentPage . pageIndex ) {
// if ( upperNumber ! = nextPage . pageIndex ) {
// // NSLog ( @ "Next was %d, now %d (A)" , nextPage . pageIndex , upperNumber ) ;
2012-11-14 17:31:52 -08:00
// [ self applyNewIndex : upperNumber pageController : nextPage ] ;
2020-10-30 20:58:27 -07:00
// }
// if ( previousNumber ! = previousPage . pageIndex ) {
// // NSLog ( @ "Prev was %d, now %d (A)" , previousPage . pageIndex , previousNumber ) ;
// [ self applyNewIndex : previousNumber pageController : previousPage ] ;
// }
// } else if ( upperNumber = = currentPage . pageIndex ) {
// // Going backwards
// if ( lowerNumber ! = previousPage . pageIndex ) {
// // NSLog ( @ "Prev was %d, now %d (B)" , previousPage . pageIndex , previousNumber ) ;
// [ self applyNewIndex : lowerNumber pageController : previousPage ] ;
// }
// } else {
// // Going forwards
// if ( lowerNumber = = nextPage . pageIndex ) {
// // NSLog ( @ "Prev was %d, now %d (C1)" , previousPage . pageIndex , previousNumber ) ;
// // [ self applyNewIndex : upperNumber pageController : nextPage ] ;
// // [ self applyNewIndex : lowerNumber pageController : currentPage ] ;
// [ self applyNewIndex : previousNumber pageController : previousPage ] ;
// } else if ( upperNumber = = nextPage . pageIndex ) {
// // NSLog ( @ "Prev was %d, now %d (C2)" , previousPage . pageIndex , previousNumber ) ;
2012-11-14 17:31:52 -08:00
// [ self applyNewIndex : lowerNumber pageController : currentPage ] ;
2020-10-30 20:58:27 -07:00
// [ self applyNewIndex : previousNumber pageController : previousPage ] ;
// } else {
// // NSLog ( @ "Next was %d, now %d (C3)" , nextPage . pageIndex , upperNumber ) ;
// // NSLog ( @ "Current was %d, now %d (C3)" , currentPage . pageIndex , lowerNumber ) ;
// // NSLog ( @ "Prev was %d, now %d (C3)" , previousPage . pageIndex , previousNumber ) ;
// [ self applyNewIndex : lowerNumber pageController : currentPage ] ;
// [ self applyNewIndex : upperNumber pageController : nextPage ] ;
// [ self applyNewIndex : previousNumber pageController : previousPage ] ;
// }
// }
//
// // if ( self . isDraggingScrollview ) {
// [ self setStoryFromScroll ] ;
// // }
//
// [ self showAutoscrollBriefly : YES ] ;
//
// // Stick to bottom
// traversePinned = YES ;
//
// if ( ! self . isPhoneOrCompact ) {
// self . traverseBottomConstraint . constant = 0 ;
// } else {
// self . traverseBottomConstraint . constant = -1 * self . view . safeAreaInsets . bottom / 2 ;
2012-11-26 09:54:20 -08:00
// }
2020-10-30 20:58:27 -07:00
//
// [ UIView animateWithDuration : .24 delay : 0
// options : UIViewAnimationOptionCurveEaseInOut
// animations : ^ {
// [ self . traverseView setNeedsLayout ] ;
// // self . traverseView . frame = CGRectMake ( tvf . origin . x ,
// // self . scrollView . bounds . size . height - tvf . size . height - bottomSizeHeightConstraint . constant - ( self . view . safeAreaInsets . bottom - 20 ) ,
// // tvf . size . width , tvf . size . height ) ;
// self . traverseView . alpha = 1 ;
// self . traversePinned = YES ;
// [ self . view layoutIfNeeded ] ;
// } completion : ^ ( BOOL finished ) {
//
// } ] ;
2012-11-05 15:12:42 -08:00
}
2012-11-08 18:30:45 -08:00
- ( void ) scrollViewWillBeginDragging : ( UIScrollView * ) scrollView {
self . isDraggingScrollview = YES ;
}
2012-11-14 17:31:52 -08:00
- ( void ) scrollViewDidEndDecelerating : ( UIScrollView * ) newScrollView
{
[ self scrollViewDidEndScrollingAnimation : newScrollView ] ;
}
2012-11-05 15:12:42 -08:00
- ( void ) scrollViewDidEndScrollingAnimation : ( UIScrollView * ) newScrollView
{
2012-11-08 18:30:45 -08:00
self . isDraggingScrollview = NO ;
2018-08-30 16:33:42 -07:00
CGSize size = self . scrollView . frame . size ;
CGPoint offset = self . scrollView . contentOffset ;
CGFloat pageAmount = self . isHorizontal ? size . width : size . height ;
float fractionalPage = ( self . isHorizontal ? offset . x : offset . y ) / pageAmount ;
2012-11-14 17:31:52 -08:00
NSInteger nearestNumber = lround ( fractionalPage ) ;
self . scrollingToPage = nearestNumber ;
2012-11-08 17:39:32 -08:00
[ self setStoryFromScroll ] ;
2012-11-05 15:12:42 -08:00
}
2013-10-03 13:54:15 -07:00
- ( void ) observeValueForKeyPath : ( NSString * ) keyPath
ofObject : ( id ) object
change : ( NSDictionary * ) change
context : ( void * ) context {
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact &&
2013-02-06 15:15:43 -08:00
[ keyPath isEqual : @ "contentOffset" ] &&
2012-11-19 19:15:05 -08:00
self . isDraggingScrollview ) {
2018-08-30 16:33:42 -07:00
CGSize size = self . scrollView . frame . size ;
CGPoint offset = self . scrollView . contentOffset ;
CGFloat pageAmount = self . isHorizontal ? size . width : size . height ;
float fractionalPage = ( self . isHorizontal ? offset . x : offset . y ) / pageAmount ;
2012-11-08 18:30:45 -08:00
NSInteger nearestNumber = lround ( fractionalPage ) ;
2014-02-12 20:09:37 -08:00
if ( ! [ appDelegate . storiesCollection . activeFeedStories count ] ) return ;
2012-11-28 15:21:44 -08:00
2018-08-30 16:33:42 -07:00
// NSLog ( @ "observe content offset: fractional page %@" , @ ( fractionalPage ) ) ; // log
2014-02-12 20:09:37 -08:00
NSInteger storyIndex = [ appDelegate . storiesCollection indexFromLocation : nearestNumber ] ;
2015-11-28 22:07:38 -08:00
if ( storyIndex ! = [ appDelegate . storiesCollection indexOfActiveStory ] && storyIndex ! = NSNotFound ) {
2014-02-12 20:09:37 -08:00
appDelegate . activeStory = [ appDelegate . storiesCollection . activeFeedStories
objectAtIndex : storyIndex ] ;
2012-11-19 19:15:05 -08:00
[ appDelegate changeActiveFeedDetailRow ] ;
}
2012-11-08 18:30:45 -08:00
}
}
2014-02-24 18:35:35 -08:00
- ( void ) animateIntoPlace : ( BOOL ) animated {
2014-01-30 20:28:08 -08:00
// Move view into position if no story is selected yet
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact &&
2014-01-30 20:28:08 -08:00
! self . isAnimatedIntoPlace ) {
CGRect frame = self . scrollView . frame ;
2018-08-30 16:33:42 -07:00
if ( self . isHorizontal ) {
frame . origin . x = frame . size . width ;
} else {
frame . origin . y = frame . size . height ;
}
2014-01-30 20:28:08 -08:00
self . scrollView . frame = frame ;
2018-08-30 16:33:42 -07:00
2014-02-24 18:35:35 -08:00
[ UIView animateWithDuration : ( animated ? .22 : 0 ) delay : 0
options : UIViewAnimationOptionCurveEaseInOut
animations : ^
{
2014-01-30 20:28:08 -08:00
CGRect frame = self . scrollView . frame ;
2018-08-30 16:33:42 -07:00
if ( self . isHorizontal ) {
frame . origin . x = 0 ;
} else {
frame . origin . y = 0 ;
}
2014-01-30 20:28:08 -08:00
self . scrollView . frame = frame ;
} completion : ^ ( BOOL finished ) {
self . isAnimatedIntoPlace = YES ;
} ] ;
}
}
2012-11-05 18:23:45 -08:00
- ( void ) changePage : ( NSInteger ) pageIndex {
2012-11-09 11:39:36 -08:00
[ self changePage : pageIndex animated : YES ] ;
}
- ( void ) changePage : ( NSInteger ) pageIndex animated : ( BOOL ) animated {
2018-08-30 16:33:42 -07:00
// NSLog ( @ "changePage to %@ (%@animated)" , @ ( pageIndex ) , animated ? @ "" : @ "not " ) ;
2012-11-05 18:23:45 -08:00
// update the scroll view to the appropriate page
2012-11-06 17:26:08 -08:00
[ self resizeScrollView ] ;
2020-10-30 20:58:27 -07:00
# warning obsolete
// CGRect frame = self . scrollView . frame ;
// CGPoint offset = self . scrollView . contentOffset ;
//
// if ( self . isHorizontal ) {
// frame . origin . x = frame . size . width * pageIndex ;
// frame . origin . y = 0 ;
// } else {
// frame . origin . x = 0 ;
// frame . origin . y = ( frame . size . height * pageIndex ) - self . view . safeAreaInsets . bottom ;
// }
2012-11-09 14:57:33 -08:00
2012-11-14 17:31:52 -08:00
self . scrollingToPage = pageIndex ;
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController hideNoStoryMessage ] ;
} ] ;
2013-09-12 21:26:38 -07:00
2012-11-28 15:46:11 -08:00
// Check if already on the selected page
2020-10-30 20:58:27 -07:00
// if ( self . isHorizontal ? offset . x = = frame . origin . x : offset . y = = frame . origin . y ) {
[ self applyNewIndex : pageIndex pageController : self . currentStoryController ] ;
2012-11-08 17:39:32 -08:00
[ self setStoryFromScroll ] ;
2020-10-30 20:58:27 -07:00
# warning obsolete
// } else {
// [ self . scrollView scrollRectToVisible : frame animated : animated ] ;
// if ( ! animated ) {
// [ self setStoryFromScroll ] ;
// }
// }
2015-11-22 21:11:23 -05:00
[ self becomeFirstResponder ] ;
2015-11-21 23:23:37 -05:00
}
- ( void ) changeToNextPage : ( id ) sender {
2020-10-30 20:58:27 -07:00
[ self changePage : self . currentStoryController . pageIndex + 1 animated : YES ] ;
2015-11-21 23:23:37 -05:00
}
- ( void ) changeToPreviousPage : ( id ) sender {
2020-10-30 20:58:27 -07:00
[ self changePage : self . currentStoryController . pageIndex - 1 animated : YES ] ;
2012-11-05 18:23:45 -08:00
}
2012-11-08 17:39:32 -08:00
- ( void ) setStoryFromScroll {
2012-11-26 09:54:20 -08:00
[ self setStoryFromScroll : NO ] ;
}
- ( void ) setStoryFromScroll : ( BOOL ) force {
2020-10-30 20:58:27 -07:00
# warning somewhat obsolete ; may be some stuff needed here
// CGSize size = self . scrollView . bounds . size ;
// CGPoint offset = self . scrollView . contentOffset ;
// CGFloat pageAmount = self . isHorizontal ? size . width : size . height ;
// float fractionalPage = ( self . isHorizontal ? offset . x : offset . y ) / pageAmount ;
// NSInteger nearestNumber = lround ( fractionalPage ) ;
//
// // NSLog ( @ "setStoryFromScroll: fractional page %@" , @ ( fractionalPage ) ) ; // log
//
// if ( ! force && currentPage . pageIndex >= 0 &&
// currentPage . pageIndex = = nearestNumber &&
// currentPage . pageIndex ! = self . scrollingToPage ) {
// // NSLog ( @ "Skipping setStoryFromScroll: currentPage is %@ (%@, %@)" , @ ( currentPage . pageIndex ) , @ ( nearestNumber ) , @ ( self . scrollingToPage ) ) ;
// return ;
// }
//
// if ( currentPage . pageIndex < nearestNumber ) {
// // NSLog ( @ "Swap next into current, current into previous: %@ / %@" , @ ( currentPage . pageIndex ) , @ ( nearestNumber ) ) ;
// StoryDetailViewController * swapCurrentController = currentPage ;
// StoryDetailViewController * swapPreviousController = previousPage ;
// currentPage = nextPage ;
// previousPage = swapCurrentController ;
// nextPage = swapPreviousController ;
// } else if ( currentPage . pageIndex > nearestNumber ) {
// // NSLog ( @ "Swap previous into current: %@ / %@" , @ ( currentPage . pageIndex ) , @ ( nearestNumber ) ) ;
// StoryDetailViewController * swapCurrentController = currentPage ;
// StoryDetailViewController * swapNextController = nextPage ;
// currentPage = previousPage ;
// nextPage = swapCurrentController ;
// previousPage = swapNextController ;
// }
//
// // NSLog ( @ "Set Story from scroll: %@ = %@ (%@/%@/%@)" , @ ( fractionalPage ) , @ ( nearestNumber ) , @ ( previousPage . pageIndex ) , @ ( currentPage . pageIndex ) , @ ( nextPage . pageIndex ) ) ;
2019-02-28 15:29:31 -08:00
self . autoscrollActive = NO ;
2020-10-30 20:58:27 -07:00
// // [ self showAutoscrollBriefly : YES ] ;
//
// nextPage . webView . scrollView . scrollsToTop = NO ;
// previousPage . webView . scrollView . scrollsToTop = NO ;
// currentPage . webView . scrollView . scrollsToTop = YES ;
self . currentStoryController . isRecentlyUnread = NO ;
// if ( ! self . isPhoneOrCompact ) {
// appDelegate . feedDetailViewController . storyTitlesTable . scrollsToTop = NO ;
// }
// self . scrollView . scrollsToTop = NO ;
//
// if ( self . isDraggingScrollview || self . scrollingToPage = = currentPage . pageIndex ) {
if ( self . currentStoryController . pageIndex = = -2 ) return ;
2012-11-26 09:54:20 -08:00
self . scrollingToPage = -1 ;
2020-10-30 20:58:27 -07:00
NSInteger storyIndex = [ appDelegate . storiesCollection indexFromLocation : self . currentStoryController . pageIndex ] ;
2018-08-30 16:33:42 -07:00
if ( storyIndex < 0 ) {
2020-10-30 20:58:27 -07:00
NSLog ( @ "invalid story index: %@ for page index: %@" , @ ( storyIndex ) , @ ( self . currentStoryController . pageIndex ) ) ; // log
[ self doNextUnreadStory : nil ] ;
return ;
2018-08-30 16:33:42 -07:00
}
2014-02-12 20:09:37 -08:00
appDelegate . activeStory = [ appDelegate . storiesCollection . activeFeedStories objectAtIndex : storyIndex ] ;
2020-10-30 20:58:27 -07:00
[ self updatePageWithActiveStory : self . currentStoryController . pageIndex ] ;
2014-03-05 14:13:49 -08:00
if ( [ appDelegate . storiesCollection isStoryUnread : appDelegate . activeStory ] ) {
[ appDelegate . storiesCollection markStoryRead : appDelegate . activeStory ] ;
[ appDelegate . storiesCollection syncStoryAsRead : appDelegate . activeStory ] ;
}
[ appDelegate . feedDetailViewController redrawUnreadStory ] ;
2020-10-30 20:58:27 -07:00
// }
2020-07-21 20:00:09 -07:00
if ( ! appDelegate . storiesCollection . inSearch ) {
2020-10-30 20:58:27 -07:00
[ self . currentStoryController becomeFirstResponder ] ;
2020-07-21 20:00:09 -07:00
}
2012-11-08 17:39:32 -08:00
}
2012-12-13 16:41:52 -08:00
- ( void ) advanceToNextUnread {
2019-03-22 20:55:22 -07:00
if ( self . restoringStoryId . length > 0 ) {
[ self restorePage ] ;
return ;
}
2012-12-13 16:41:52 -08:00
if ( ! self . waitingForNextUnreadFromServer ) {
return ;
}
self . waitingForNextUnreadFromServer = NO ;
2013-10-08 13:57:15 -07:00
[ self doNextUnreadStory : nil ] ;
2012-12-13 16:41:52 -08:00
}
2013-09-25 10:47:35 -07:00
- ( void ) updatePageWithActiveStory : ( NSInteger ) location {
2014-02-12 20:41:29 -08:00
[ appDelegate . storiesCollection pushReadStory : [ appDelegate . activeStory objectForKey : @ "story_hash" ] ] ;
2012-11-05 17:16:10 -08:00
2015-09-23 13:02:25 -07:00
// [ self . view setNeedsLayout ] ;
2012-11-05 17:16:10 -08:00
2020-03-29 16:21:00 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
2020-11-24 21:34:45 -08:00
if ( appDelegate . detailViewController . storyTitlesOnLeft ) {
2017-11-01 22:19:26 -07:00
self . navigationItem . rightBarButtonItems = [ NSArray arrayWithObjects :
originalStoryButton ,
separatorBarButton ,
fontSettingsButton , nil ] ;
} else {
self . navigationItem . rightBarButtonItems = [ NSArray arrayWithObjects :
originalStoryButton ,
separatorBarButton ,
fontSettingsButton ,
separatorBarButton2 ,
markReadBarButton , nil ] ;
}
2013-03-04 17:15:50 -08:00
}
2012-11-05 17:16:10 -08:00
[ self setNextPreviousButtons ] ;
2020-10-30 20:58:27 -07:00
# warning not using EventWindow currently , so this crashes ; evaluate
// EventWindow * tapDetectingWindow = ( EventWindow * ) self . view . window ;
// tapDetectingWindow . tapDetectingView = self . currentStoryController . view ;
2012-11-07 17:54:16 -08:00
[ appDelegate changeActiveFeedDetailRow ] ;
2012-11-08 17:39:32 -08:00
2020-10-30 20:58:27 -07:00
if ( self . currentStoryController . pageIndex ! = location ) {
// NSLog ( @ "Updating Current: from %d to %d" , self . currentStoryController . pageIndex , location ) ;
[ self applyNewIndex : location pageController : self . currentStoryController ] ;
2012-11-14 17:31:52 -08:00
}
2020-10-30 20:58:27 -07:00
# warning obsolete
// if ( self . nextPage . pageIndex ! = location + 1 ) {
// // NSLog ( @ "Updating Next: from %d to %d" , nextPage . pageIndex , location + 1 ) ;
// [ self applyNewIndex : location + 1 pageController : self . nextPage ] ;
// }
// if ( self . previousPage . pageIndex ! = location -1 ) {
// // NSLog ( @ "Updating Previous: from %d to %d" , previousPage . pageIndex , location -1 ) ;
// [ self applyNewIndex : location -1 pageController : self . previousPage ] ;
// }
2012-11-05 15:12:42 -08:00
}
2013-02-06 18:42:15 -08:00
- ( void ) requestFailed : ( id ) request {
2013-09-06 14:31:12 -07:00
[ self informError : @ "The server barfed!" ] ;
2012-11-05 17:16:10 -08:00
}
# pragma mark -
# pragma mark Actions
2017-11-01 22:19:26 -07:00
- ( IBAction ) markAllRead : ( id ) sender {
[ appDelegate . feedDetailViewController doOpenMarkReadMenu : markReadBarButton ] ;
}
2012-11-05 17:16:10 -08:00
- ( void ) setNextPreviousButtons {
// setting up the PREV BUTTON
2013-09-25 10:47:35 -07:00
NSInteger readStoryCount = [ appDelegate . readStories count ] ;
2012-11-05 17:16:10 -08:00
if ( readStoryCount = = 0 ||
( readStoryCount = = 1 &&
2014-02-12 20:41:29 -08:00
[ appDelegate . readStories lastObject ] = = [ appDelegate . activeStory objectForKey : @ "story_hash" ] ) ) {
2013-07-19 16:49:48 -07:00
[ buttonPrevious setEnabled : NO ] ;
} else {
[ buttonPrevious setEnabled : YES ] ;
}
2012-11-05 17:16:10 -08:00
2018-08-30 16:33:42 -07:00
NSString * previousName = self . isHorizontal ? @ "traverse_previous.png" : @ "traverse_previous_vert.png" ;
NSString * previousNameOff = self . isHorizontal ? @ "traverse_previous_off.png" : @ "traverse_previous_off_vert.png" ;
[ buttonPrevious setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : previousName ] ]
2015-12-07 16:09:49 -08:00
forState : UIControlStateNormal ] ;
2018-08-30 16:33:42 -07:00
[ buttonPrevious setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : previousNameOff ] ]
forState : UIControlStateDisabled ] ;
2015-12-07 16:09:49 -08:00
2012-11-05 17:16:10 -08:00
// setting up the NEXT UNREAD STORY BUTTON
2013-03-05 17:00:03 -08:00
buttonNext . enabled = YES ;
2014-02-12 20:09:37 -08:00
NSInteger nextIndex = [ appDelegate . storiesCollection indexOfNextUnreadStory ] ;
2013-09-25 10:47:35 -07:00
NSInteger unreadCount = [ appDelegate unreadCount ] ;
2017-04-03 16:07:01 -07:00
BOOL pageFinished = appDelegate . feedDetailViewController . pageFinished ;
2014-04-18 14:48:38 -07:00
if ( ( nextIndex = = -1 && unreadCount > 0 && ! pageFinished ) ||
2013-03-05 17:00:03 -08:00
nextIndex ! = -1 ) {
2018-08-30 16:33:42 -07:00
NSString * nextName = self . isHorizontal ? @ "traverse_next.png" : @ "traverse_next_vert.png" ;
2013-10-02 16:05:22 -07:00
[ buttonNext setTitle : [ @ "Next" uppercaseString ] forState : UIControlStateNormal ] ;
2018-08-30 16:33:42 -07:00
[ buttonNext setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : nextName ] ]
2013-10-03 13:54:15 -07:00
forState : UIControlStateNormal ] ;
2012-11-05 17:16:10 -08:00
} else {
2013-10-02 16:05:22 -07:00
[ buttonNext setTitle : [ @ "Done" uppercaseString ] forState : UIControlStateNormal ] ;
2015-12-07 16:09:49 -08:00
[ buttonNext setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_done.png" ] ]
2013-10-03 13:54:15 -07:00
forState : UIControlStateNormal ] ;
2012-11-05 17:16:10 -08:00
}
float unreads = ( float ) [ appDelegate unreadCount ] ;
float total = [ appDelegate originalStoryCount ] ;
float progress = ( total - unreads ) / total ;
2013-04-10 21:06:17 -07:00
circularProgressView . percentage = progress ;
2012-11-05 17:16:10 -08:00
}
2013-05-29 13:36:39 -07:00
- ( void ) setTextButton {
2020-10-30 20:58:27 -07:00
[ self setTextButton : self . currentStoryController ] ;
2015-03-09 14:20:45 -07:00
}
- ( void ) setTextButton : ( StoryDetailViewController * ) storyViewController {
2020-10-30 20:58:27 -07:00
if ( storyViewController ! = self . currentStoryController ) return ;
2015-03-09 14:20:45 -07:00
if ( storyViewController . pageIndex >= 0 ) {
2013-05-30 16:31:57 -07:00
[ buttonText setEnabled : YES ] ;
[ buttonText setAlpha : 1 ] ;
2013-07-19 18:19:30 -07:00
[ buttonSend setEnabled : YES ] ;
[ buttonSend setAlpha : 1 ] ;
2013-05-30 16:31:57 -07:00
} else {
[ buttonText setEnabled : NO ] ;
[ buttonText setAlpha : .4 ] ;
2013-07-19 18:19:30 -07:00
[ buttonSend setEnabled : NO ] ;
[ buttonSend setAlpha : .4 ] ;
2013-05-30 16:31:57 -07:00
}
2015-12-07 16:09:49 -08:00
[ buttonSend setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_send.png" ] ]
forState : UIControlStateNormal ] ;
2015-03-09 14:20:45 -07:00
if ( storyViewController . inTextView ) {
2013-05-29 13:36:39 -07:00
[ buttonText setTitle : [ @ "Story" uppercaseString ] forState : UIControlStateNormal ] ;
2015-12-07 16:09:49 -08:00
[ buttonText setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_text_on.png" ] ]
2016-10-05 21:03:32 -07:00
forState : 0 ] ;
2013-10-02 17:31:51 -07:00
self . buttonText . titleEdgeInsets = UIEdgeInsetsMake ( 0 , 26 , 0 , 0 ) ;
2013-05-29 13:36:39 -07:00
} else {
[ buttonText setTitle : [ @ "Text" uppercaseString ] forState : UIControlStateNormal ] ;
2015-12-07 16:09:49 -08:00
[ buttonText setBackgroundImage : [ [ ThemeManager themeManager ] themedImage : [ UIImage imageNamed : @ "traverse_text.png" ] ]
2016-10-05 21:03:32 -07:00
forState : 0 ] ;
2013-10-02 17:31:51 -07:00
self . buttonText . titleEdgeInsets = UIEdgeInsetsMake ( 0 , 22 , 0 , 0 ) ;
2013-05-29 13:36:39 -07:00
}
}
2013-07-19 16:49:48 -07:00
- ( IBAction ) openSendToDialog : ( id ) sender {
2013-10-08 13:57:15 -07:00
[ self endTouchDown : sender ] ;
2014-01-06 18:37:57 -08:00
[ appDelegate showSendTo : self sender : sender ] ;
2012-11-05 17:16:10 -08:00
}
2015-11-24 15:39:07 -05:00
- ( void ) openStoryTrainerFromKeyboard : ( id ) sender {
// don ' t have a tap target for the popover , but the settings button at least doesn ' t move
[ appDelegate openTrainStory : self . fontSettingsButton ] ;
}
2017-03-19 18:15:36 -07:00
- ( void ) finishMarkAsSaved : ( NSDictionary * ) params {
2013-08-05 17:29:42 -07:00
[ appDelegate . feedDetailViewController redrawUnreadStory ] ;
[ self refreshHeaders ] ;
2020-10-30 20:58:27 -07:00
[ self . currentStoryController flashCheckmarkHud : @ "saved" ] ;
2012-11-05 17:16:10 -08:00
}
2017-03-19 18:15:36 -07:00
- ( BOOL ) failedMarkAsSaved : ( NSDictionary * ) params {
2017-06-01 22:32:35 -07:00
if ( ! [ [ params objectForKey : @ "story_id" ]
2020-10-30 20:58:27 -07:00
isEqualToString : [ self . currentStoryController . activeStory objectForKey : @ "story_hash" ] ] ) {
2014-03-05 14:13:49 -08:00
return NO ;
}
[ self informError : @ "Failed to save story" ] ;
2017-06-01 22:32:35 -07:00
[ appDelegate hidePopover ] ;
2014-03-05 14:13:49 -08:00
return YES ;
2012-11-05 17:16:10 -08:00
}
2017-03-19 18:15:36 -07:00
- ( void ) finishMarkAsUnsaved : ( NSDictionary * ) params {
[ appDelegate . storiesCollection markStory : [ params objectForKey : @ "story" ] asSaved : NO ] ;
2013-08-05 17:29:42 -07:00
[ appDelegate . feedDetailViewController redrawUnreadStory ] ;
[ self refreshHeaders ] ;
2020-10-30 20:58:27 -07:00
[ self . currentStoryController flashCheckmarkHud : @ "unsaved" ] ;
2012-11-05 17:16:10 -08:00
}
2017-03-19 18:15:36 -07:00
- ( BOOL ) failedMarkAsUnsaved : ( NSDictionary * ) params {
2017-06-01 22:32:35 -07:00
if ( ! [ [ params objectForKey : @ "story_id" ]
2020-10-30 20:58:27 -07:00
isEqualToString : [ self . currentStoryController . activeStory objectForKey : @ "story_hash" ] ] ) {
2014-03-05 14:13:49 -08:00
return NO ;
2012-11-05 17:16:10 -08:00
}
2014-03-05 14:13:49 -08:00
[ self informError : @ "Failed to unsave story" ] ;
return YES ;
2012-11-05 17:16:10 -08:00
}
2017-03-19 18:15:36 -07:00
- ( BOOL ) failedMarkAsUnread : ( NSDictionary * ) params {
2017-06-01 22:32:35 -07:00
if ( ! [ [ params objectForKey : @ "story_id" ]
2020-10-30 20:58:27 -07:00
isEqualToString : [ self . currentStoryController . activeStory objectForKey : @ "story_hash" ] ] ) {
2014-03-05 14:13:49 -08:00
return NO ;
2013-10-03 18:07:39 -07:00
}
2013-10-04 12:37:51 -07:00
2014-03-05 14:13:49 -08:00
[ self informError : @ "Failed to unread story" ] ;
return YES ;
2013-10-03 18:07:39 -07:00
}
2012-11-05 17:16:10 -08:00
- ( IBAction ) showOriginalSubview : ( id ) sender {
2015-12-15 12:37:18 -08:00
[ appDelegate hidePopover ] ;
2020-04-22 20:18:06 -07:00
NSString * permalink = [ appDelegate . activeStory objectForKey : @ "story_permalink" ] ;
NSURL * url = [ NSURL URLWithString : permalink ] ;
if ( url = = nil ) {
url = [ NSURL URLWithDataRepresentation : [ permalink dataUsingEncoding : NSUTF8StringEncoding ] relativeToURL : nil ] ;
}
2012-11-05 17:16:10 -08:00
[ appDelegate showOriginalStory : url ] ;
}
- ( IBAction ) tapProgressBar : ( id ) sender {
2020-10-30 20:58:27 -07:00
[ MBProgressHUD hideHUDForView : self . currentStoryController . webView animated : NO ] ;
MBProgressHUD * hud = [ MBProgressHUD showHUDAddedTo : self . currentStoryController . webView animated : YES ] ;
2012-11-05 17:16:10 -08:00
hud . mode = MBProgressHUDModeText ;
hud . removeFromSuperViewOnHide = YES ;
2013-09-25 17:43:00 -07:00
NSInteger unreadCount = appDelegate . unreadCount ;
2012-11-05 17:16:10 -08:00
if ( unreadCount = = 0 ) {
hud . labelText = @ "No unread stories" ;
} else if ( unreadCount = = 1 ) {
hud . labelText = @ "1 story left" ;
} else {
2013-09-25 17:43:00 -07:00
hud . labelText = [ NSString stringWithFormat : @ "%li stories left" , ( long ) unreadCount ] ;
2012-11-05 17:16:10 -08:00
}
[ hud hide : YES afterDelay : 0.8 ] ;
}
2012-11-28 16:24:15 -08:00
- ( void ) subscribeToBlurblog {
2020-10-30 20:58:27 -07:00
[ self . currentStoryController subscribeToBlurblog ] ;
2012-11-28 16:24:15 -08:00
}
2012-11-05 17:16:10 -08:00
2015-03-11 11:21:59 -07:00
- ( IBAction ) toggleTextView : ( id ) sender {
2013-10-08 13:57:15 -07:00
[ self endTouchDown : sender ] ;
2015-10-05 11:45:33 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" ,
[ appDelegate . activeStory objectForKey : @ "story_feed_id" ] ] ;
[ appDelegate toggleFeedTextView : feedIdStr ] ;
2013-10-08 13:57:15 -07:00
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController showTextOrStoryView ] ;
} ] ;
2013-05-28 18:07:19 -07:00
}
2015-11-21 23:23:37 -05:00
- ( void ) toggleStorySaved : ( id ) sender {
[ appDelegate . storiesCollection toggleStorySaved ] ;
}
- ( void ) toggleStoryUnread : ( id ) sender {
[ appDelegate . storiesCollection toggleStoryUnread ] ;
[ appDelegate . feedDetailViewController redrawUnreadStory ] ; // XXX only if successful ?
}
2015-11-24 13:52:16 -05:00
- ( BOOL ) canPerformAction : ( SEL ) action withSender : ( id ) sender {
if ( action = = @ selector ( toggleTextView : ) ||
action = = @ selector ( scrollPageDown : ) ||
action = = @ selector ( scrollPageUp : ) ||
action = = @ selector ( toggleStoryUnread : ) ||
action = = @ selector ( toggleStorySaved : ) ||
action = = @ selector ( showOriginalSubview : ) ||
action = = @ selector ( openShareDialog ) ||
2015-11-24 15:39:07 -05:00
action = = @ selector ( scrolltoComment ) ||
action = = @ selector ( openStoryTrainerFromKeyboard : ) ) {
2020-10-30 20:58:27 -07:00
return ( self . currentStoryController . pageIndex >= 0 ) ;
2015-11-24 13:52:16 -05:00
}
return [ super canPerformAction : action withSender : sender ] ;
}
2012-11-05 17:16:10 -08:00
# pragma mark -
# pragma mark Styles
2015-10-31 16:35:32 -07:00
- ( IBAction ) toggleFontSize : ( id ) sender {
2017-04-03 16:07:01 -07:00
UINavigationController * fontSettingsNavigationController = appDelegate . fontSettingsNavigationController ;
2016-03-19 13:19:06 -04:00
[ fontSettingsNavigationController popToRootViewControllerAnimated : NO ] ;
2017-04-03 16:07:01 -07:00
[ appDelegate showPopoverWithViewController : fontSettingsNavigationController contentSize : CGSizeZero barButtonItem : self . fontSettingsButton ] ;
2012-11-05 17:16:10 -08:00
}
2012-11-09 14:13:44 -08:00
- ( void ) setFontStyle : ( NSString * ) fontStyle {
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController setFontStyle : fontStyle ] ;
} ] ;
2012-11-09 14:13:44 -08:00
}
- ( void ) changeFontSize : ( NSString * ) fontSize {
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController changeFontSize : fontSize ] ;
} ] ;
2012-11-09 14:13:44 -08:00
}
2014-05-15 18:06:56 -07:00
- ( void ) changeLineSpacing : ( NSString * ) lineSpacing {
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController changeLineSpacing : lineSpacing ] ;
} ] ;
2014-05-15 18:06:56 -07:00
}
2019-02-27 13:33:38 -08:00
- ( void ) changedFullscreen {
2020-06-20 21:31:21 -07:00
BOOL wantHidden = self . allowFullscreen ;
2019-02-27 13:33:38 -08:00
2020-06-20 21:31:21 -07:00
self . navigationController . hidesBarsOnSwipe = self . allowFullscreen ;
[ self setNavigationBarHidden : wantHidden alsoTraverse : YES ] ;
2019-02-27 13:33:38 -08:00
}
- ( void ) changedAutoscroll {
2019-02-28 15:29:31 -08:00
self . autoscrollActive = self . autoscrollAvailable ;
2019-02-27 13:33:38 -08:00
}
2018-09-05 13:51:33 -07:00
- ( void ) changedScrollOrientation {
[ self . scrollView setAlwaysBounceHorizontal : self . isHorizontal ] ;
[ self . scrollView setAlwaysBounceVertical : ! self . isHorizontal ] ;
[ self reorientPages ] ;
}
2018-10-22 15:14:12 -07:00
- ( void ) updateStoriesTheme {
2020-10-30 20:58:27 -07:00
[ self updateStoryControllers : ^ ( StoryDetailViewController * storyController ) {
[ storyController updateStoryTheme ] ;
} ] ;
2015-12-07 16:09:49 -08:00
}
2020-04-22 19:31:08 -07:00
- ( void ) updateStatusBarTheme {
2020-09-22 17:28:14 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone ) {
2020-04-24 20:58:20 -07:00
[ self . statusBarBackgroundView removeFromSuperview ] ;
2020-04-22 19:31:08 -07:00
2020-04-24 20:58:20 -07:00
CGRect statusRect = CGRectMake ( 0 , 0 , self . view . bounds . size . width , self . statusBarHeight ) ;
2020-04-22 19:31:08 -07:00
2020-04-24 20:58:20 -07:00
self . statusBarBackgroundView = [ [ UIView alloc ] initWithFrame : statusRect ] ;
self . statusBarBackgroundView . backgroundColor = self . navigationController . navigationBar . barTintColor ;
2020-04-22 19:31:08 -07:00
2020-06-28 17:09:50 -07:00
[ self . navigationController . view addSubview : self . statusBarBackgroundView ] ;
2020-04-24 20:58:20 -07:00
self . statusBarBackgroundView . autoresizingMask = UIViewAutoresizingFlexibleBottomMargin ;
2020-04-22 19:31:08 -07:00
[ self updateStatusBarState ] ;
}
}
2015-11-22 21:11:23 -05:00
- ( void ) backToDashboard : ( id ) sender {
UINavigationController * feedDetailNavigationController = appDelegate . feedDetailViewController . navigationController ;
if ( feedDetailNavigationController ! = nil )
[ feedDetailNavigationController popViewControllerAnimated : YES ] ;
[ self transitionFromFeedDetail ] ;
}
2013-07-13 16:56:33 +02:00
# pragma mark -
# pragma mark HUDs
2012-11-09 14:13:44 -08:00
- ( void ) showShareHUD : ( NSString * ) msg {
2018-07-13 15:25:27 -04:00
[ MBProgressHUD hideHUDForView : self . view animated : NO ] ;
2020-10-30 20:58:27 -07:00
self . storyHUD = [ MBProgressHUD showHUDAddedTo : self . currentStoryController . view animated : YES ] ;
2012-11-09 14:13:44 -08:00
self . storyHUD . labelText = msg ;
self . storyHUD . margin = 20.0 f ;
2018-07-13 15:25:27 -04:00
self . storyHUD . removeFromSuperViewOnHide = YES ;
2020-10-30 20:58:27 -07:00
self . currentStoryController . noStoryMessage . hidden = YES ;
2012-11-09 14:13:44 -08:00
}
2013-07-13 16:56:33 +02:00
- ( void ) flashCheckmarkHud : ( NSString * ) messageType {
2020-10-30 20:58:27 -07:00
[ self . currentStoryController flashCheckmarkHud : messageType ] ;
2013-07-13 16:56:33 +02:00
}
2015-10-28 21:50:23 -07:00
- ( void ) showFetchingTextNotifier {
self . notifier . style = NBSyncingStyle ;
self . notifier . title = @ "Fetching text..." ;
[ self . notifier setProgress : 0 ] ;
[ self . notifier show ] ;
}
- ( void ) hideNotifier {
[ self . notifier hide ] ;
}
2019-02-28 15:29:31 -08:00
# pragma mark -
# pragma mark Story Autoscroll
- ( BOOL ) autoscrollAvailable {
return [ [ NSUserDefaults standardUserDefaults ] boolForKey : @ "story_autoscroll" ] ;
}
- ( void ) setAutoscrollAvailable : ( BOOL ) available {
[ [ NSUserDefaults standardUserDefaults ] setBool : available forKey : @ "story_autoscroll" ] ;
}
- ( NSTimeInterval ) autoscrollSpeed {
CGFloat speed = [ [ NSUserDefaults standardUserDefaults ] doubleForKey : @ "story_autoscroll_speed" ] ;
if ( speed <= 0 ) {
speed = 0.03 ;
}
return speed ;
}
- ( void ) setAutoscrollSpeed : ( NSTimeInterval ) speed {
[ [ NSUserDefaults standardUserDefaults ] setDouble : speed forKey : @ "story_autoscroll_speed" ] ;
// This will update the timer with the new speed .
self . autoscrollActive = self . autoscrollActive ;
NSLog ( @ "set autoscroll speed to: %@" , @ ( speed ) ) ; // log
}
- ( BOOL ) autoscrollActive {
return self . autoscrollTimer ! = nil ;
}
- ( void ) setAutoscrollActive : ( BOOL ) active {
[ self . autoscrollTimer invalidate ] ;
self . autoscrollTimer = nil ;
if ( active && self . autoscrollAvailable ) {
self . autoscrollTimer = [ NSTimer scheduledTimerWithTimeInterval : self . autoscrollSpeed target : self selector : @ selector ( autoscroll : ) userInfo : nil repeats : YES ] ;
}
[ self updateAutoscrollButtons ] ;
}
- ( void ) autoscroll : ( NSTimer * ) timer {
2020-10-30 20:58:27 -07:00
WKWebView * webView = self . currentStoryController . webView ;
2019-02-28 15:29:31 -08:00
CGFloat position = webView . scrollView . contentOffset . y + 0.5 ;
2020-09-25 20:31:01 -07:00
CGFloat maximum = ( webView . scrollView . contentSize . height - webView . frame . size . height ) + self . view . safeAreaInsets . bottom ;
2019-02-28 15:29:31 -08:00
if ( position < maximum ) {
[ webView . scrollView setContentOffset : CGPointMake ( 0 , position ) animated : NO ] ;
} else {
self . autoscrollActive = NO ;
}
}
2020-06-20 21:31:21 -07:00
- ( void ) tappedStory {
if ( self . autoscrollAvailable ) {
[ self showAutoscrollBriefly : YES ] ;
2020-07-31 16:10:09 -07:00
} else if ( self . allowFullscreen ) {
[ self setNavigationBarHidden : ! self . isNavigationBarHidden ] ;
2020-06-20 21:31:21 -07:00
}
}
2019-02-28 15:29:31 -08:00
- ( void ) showAutoscrollBriefly : ( BOOL ) briefly {
2020-10-30 20:58:27 -07:00
if ( ! self . autoscrollAvailable || self . currentStoryController . webView . scrollView . contentSize . height - 200 <= self . currentStoryController . view . frame . size . height ) {
2019-05-16 13:58:03 -07:00
[ self hideAutoscrollWithAnimation ] ;
2019-02-28 15:29:31 -08:00
return ;
}
if ( self . autoscrollView . alpha = = 0 ) {
2019-04-16 20:24:42 -07:00
if ( self . isPhoneOrCompact ) {
self . autoscrollBottomConstraint . constant = 50 ;
} else {
2019-06-26 18:38:42 -07:00
self . autoscrollBottomConstraint . constant = 0 ;
2019-04-16 20:24:42 -07:00
}
[ self . view layoutIfNeeded ] ;
2019-02-28 15:29:31 -08:00
[ UIView animateWithDuration : 0.2 animations : ^ {
[ self . view layoutIfNeeded ] ;
self . autoscrollView . alpha = 1 ;
} ] ;
}
if ( briefly ) {
[ self hideAutoscrollAfterDelay ] ;
}
}
- ( void ) hideAutoscrollAfterDelay {
[ self . autoscrollViewTimer invalidate ] ;
2019-05-16 13:58:03 -07:00
self . autoscrollViewTimer = [ NSTimer scheduledTimerWithTimeInterval : 2 target : self selector : @ selector ( hideAutoscrollWithAnimation ) userInfo : nil repeats : NO ] ;
2019-02-28 15:29:31 -08:00
}
2019-05-16 13:58:03 -07:00
- ( void ) hideAutoscrollWithAnimation {
2019-02-28 15:29:31 -08:00
[ self . autoscrollViewTimer invalidate ] ;
self . autoscrollViewTimer = nil ;
[ UIView animateWithDuration : 1 animations : ^ {
[ self . view layoutIfNeeded ] ;
self . autoscrollView . alpha = 0 ;
} ] ;
}
2019-05-16 13:58:03 -07:00
- ( void ) hideAutoscrollImmediately {
[ self . autoscrollViewTimer invalidate ] ;
self . autoscrollViewTimer = nil ;
self . autoscrollView . alpha = 0 ;
}
2019-02-28 15:29:31 -08:00
- ( void ) resetAutoscrollViewTimerIfNeeded {
if ( self . autoscrollViewTimer ! = nil ) {
[ self hideAutoscrollAfterDelay ] ;
}
}
- ( IBAction ) autoscrollDisable : ( UIButton * ) sender {
self . autoscrollAvailable = NO ;
self . autoscrollActive = NO ;
2019-05-16 13:58:03 -07:00
[ self hideAutoscrollWithAnimation ] ;
2019-02-28 15:29:31 -08:00
}
- ( IBAction ) autoscrollPauseResume : ( UIButton * ) sender {
self . autoscrollActive = ! self . autoscrollActive ;
[ self resetAutoscrollViewTimerIfNeeded ] ;
}
- ( IBAction ) autoscrollSlower : ( UIButton * ) sender {
if ( self . autoscrollSpeed < 1 ) {
self . autoscrollSpeed = self . autoscrollSpeed * 2 ; // + 0.05 ;
} else {
NSLog ( @ "Minimum autoscroll speed reached" ) ; // log
}
[ self resetAutoscrollViewTimerIfNeeded ] ;
}
- ( IBAction ) autoscrollFaster : ( UIButton * ) sender {
if ( self . autoscrollSpeed > 0.001 ) {
self . autoscrollSpeed = self . autoscrollSpeed / 2 ; // - 0.05 ;
} else {
NSLog ( @ "Maximum autoscroll speed reached" ) ; // log
}
[ self resetAutoscrollViewTimerIfNeeded ] ;
}
2012-11-05 17:16:10 -08:00
# pragma mark -
# pragma mark Story Traversal
2013-10-08 13:57:15 -07:00
- ( IBAction ) doNextUnreadStory : ( id ) sender {
2017-04-03 16:07:01 -07:00
FeedDetailViewController * fdvc = appDelegate . feedDetailViewController ;
2014-02-12 20:09:37 -08:00
NSInteger nextLocation = [ appDelegate . storiesCollection locationOfNextUnreadStory ] ;
2013-09-25 17:43:00 -07:00
NSInteger unreadCount = [ appDelegate unreadCount ] ;
2017-04-03 16:07:01 -07:00
BOOL pageFinished = appDelegate . feedDetailViewController . pageFinished ;
2014-04-18 14:48:38 -07:00
2012-11-05 17:16:10 -08:00
[ self . loadingIndicator stopAnimating ] ;
2013-10-08 13:57:15 -07:00
[ self endTouchDown : sender ] ;
2012-12-13 17:25:52 -08:00
// NSLog ( @ "doNextUnreadStory: %d (out of %d)" , nextLocation , unreadCount ) ;
2012-12-13 16:41:52 -08:00
2014-04-18 14:48:38 -07:00
if ( nextLocation = = -1 && unreadCount > 0 && ! pageFinished &&
2014-02-27 14:49:33 -08:00
appDelegate . storiesCollection . feedPage < 100 ) {
2012-11-05 17:16:10 -08:00
[ self . loadingIndicator startAnimating ] ;
2013-04-23 11:52:34 -07:00
self . circularProgressView . hidden = YES ;
2012-11-06 17:26:08 -08:00
self . buttonNext . enabled = NO ;
// Fetch next page and see if it has the unreads .
2012-12-13 16:41:52 -08:00
self . waitingForNextUnreadFromServer = YES ;
[ fdvc fetchNextPage : nil ] ;
2012-11-06 13:45:15 -08:00
} else if ( nextLocation = = -1 ) {
2020-08-29 21:19:32 -07:00
[ appDelegate . feedsNavigationController
popToViewController : [ appDelegate . feedsNavigationController . viewControllers
2012-11-05 17:16:10 -08:00
objectAtIndex : 0 ]
animated : YES ] ;
[ appDelegate hideStoryDetailView ] ;
} else {
2012-11-06 13:45:15 -08:00
[ self changePage : nextLocation ] ;
2012-11-05 17:16:10 -08:00
}
}
2013-10-08 13:57:15 -07:00
- ( IBAction ) doPreviousStory : ( id ) sender {
[ self endTouchDown : sender ] ;
2012-11-05 17:16:10 -08:00
[ self . loadingIndicator stopAnimating ] ;
2013-04-23 11:52:34 -07:00
self . circularProgressView . hidden = NO ;
2014-02-12 20:09:37 -08:00
id previousStoryId = [ appDelegate . storiesCollection popReadStory ] ;
2014-02-12 20:41:29 -08:00
if ( ! previousStoryId || previousStoryId = = [ appDelegate . activeStory objectForKey : @ "story_hash" ] ) {
2020-08-29 21:19:32 -07:00
[ appDelegate . feedsNavigationController
popToViewController : [ appDelegate . feedsNavigationController . viewControllers
2012-11-05 17:16:10 -08:00
objectAtIndex : 0 ]
animated : YES ] ;
[ appDelegate hideStoryDetailView ] ;
} else {
2014-02-12 20:09:37 -08:00
NSInteger previousLocation = [ appDelegate . storiesCollection locationOfStoryId : previousStoryId ] ;
2012-11-06 13:45:15 -08:00
if ( previousLocation = = -1 ) {
2013-10-08 13:57:15 -07:00
return [ self doPreviousStory : sender ] ;
2012-11-05 17:16:10 -08:00
}
2012-11-05 18:23:45 -08:00
// [ appDelegate setActiveStory : [ [ appDelegate activeFeedStories ]
// objectAtIndex : previousIndex ] ] ;
// [ appDelegate changeActiveFeedDetailRow ] ;
//
2012-11-06 13:45:15 -08:00
[ self changePage : previousLocation ] ;
2012-11-05 17:16:10 -08:00
}
}
2012-11-05 15:12:42 -08:00
@ end