2010-06-25 18:36:01 -04:00
//
2020-08-27 21:26:12 -07:00
// StoryDetailObjCViewController . m
2010-06-25 18:36:01 -04:00
// NewsBlur
//
// Created by Samuel Clay on 6 / 24 / 10.
// Copyright 2010 __MyCompanyName __ . All rights reserved .
//
2013-10-02 19:01:15 -07:00
# import < AVFoundation / AVFoundation . h >
2017-04-11 15:43:42 -07:00
# import < Photos / Photos . h >
2020-08-27 21:26:12 -07:00
# import "StoryDetailObjCViewController.h"
2010-06-25 18:36:01 -04:00
# import "NewsBlurAppDelegate.h"
2012-06-18 14:31:42 -07:00
# import "FontSettingsViewController.h"
2012-07-03 17:54:36 -07:00
# import "UserProfileViewController.h"
2012-07-12 13:34:41 -07:00
# import "ShareViewController.h"
2011-10-17 09:37:16 -07:00
# import "Utilities.h"
2012-07-20 19:55:38 -07:00
# import "NSString+HTML.h"
2012-07-26 13:54:45 -07:00
# import "DataUtilities.h"
2015-09-16 21:34:41 -07:00
# import "FMDatabase.h"
2015-09-16 16:53:07 -07:00
# import "SBJson4.h"
2012-12-07 16:17:48 -08:00
# import "StringHelper.h"
2014-02-12 20:09:37 -08:00
# import "StoriesCollection.h"
2014-09-17 19:02:12 -07:00
# import "UIView+ViewController.h"
2015-09-16 21:34:41 -07:00
# import "JNWThrottledBlock.h"
2020-08-27 21:26:12 -07:00
# import "NewsBlur-Swift.h"
2010-06-25 18:36:01 -04:00
2017-11-01 21:51:56 -07:00
# define iPadPro12 ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad && ( [ UIScreen mainScreen ] . bounds . size . height = = 1366 || [ UIScreen mainScreen ] . bounds . size . width = = 1366 ) )
# define iPadPro10 ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad && ( [ UIScreen mainScreen ] . bounds . size . height = = 1112 || [ UIScreen mainScreen ] . bounds . size . width = = 1112 ) )
2016-04-06 18:14:06 -07:00
2020-08-27 21:26:12 -07:00
@ interface StoryDetailObjCViewController ( )
2016-02-05 12:19:48 -08:00
2016-08-23 20:52:34 -04:00
@ property ( nonatomic , strong ) NSString * fullStoryHTML ;
2016-02-05 12:19:48 -08:00
@ end
2020-08-27 21:26:12 -07:00
@ implementation StoryDetailObjCViewController
2010-06-25 18:36:01 -04:00
2016-02-01 10:44:59 -08:00
@ synthesize appDelegate ;
@ synthesize activeStoryId ;
@ synthesize activeStory ;
@ synthesize innerView ;
@ synthesize webView ;
@ synthesize feedTitleGradient ;
@ synthesize noStoryMessage ;
@ synthesize pullingScrollview ;
@ synthesize pageIndex ;
@ synthesize storyHUD ;
@ synthesize inTextView ;
@ synthesize isRecentlyUnread ;
2012-07-26 18:07:29 -07:00
2011-12-01 09:01:18 -08:00
# pragma mark -
# pragma mark View boilerplate
2010-06-25 18:36:01 -04:00
- ( id ) initWithNibName : ( NSString * ) nibNameOrNil bundle : ( NSBundle * ) nibBundleOrNil {
2011-03-09 18:23:55 -05:00
if ( ( self = [ super initWithNibName : nibNameOrNil bundle : nibBundleOrNil ] ) ) {
2010-06-25 18:36:01 -04:00
}
return self ;
}
2020-10-30 20:58:27 -07:00
- ( void ) dealloc {
[ self . webView . scrollView removeObserver : self forKeyPath : @ "contentOffset" ] ;
[ [ NSNotificationCenter defaultCenter ] removeObserver : self ] ;
}
2011-08-14 00:16:25 -07:00
2015-04-26 21:22:25 -07:00
- ( NSString * ) description {
2021-01-29 20:10:53 -08:00
NSString * page = appDelegate . storyPagesViewController . currentPage = = self ? @ "currentPage" : appDelegate . storyPagesViewController . previousPage = = self ? @ "previousPage" : appDelegate . storyPagesViewController . nextPage = = self ? @ "nextPage" : @ "unattached page" ;
return [ NSString stringWithFormat : @ "%@" , page ] ;
2015-04-26 21:22:25 -07:00
}
2011-08-24 10:24:02 -07:00
- ( void ) viewDidLoad {
2012-07-16 10:10:52 -07:00
[ super viewDidLoad ] ;
2020-08-29 21:19:32 -07:00
self . appDelegate = [ NewsBlurAppDelegate sharedAppDelegate ] ;
2012-07-23 15:27:20 -07:00
self . view . autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ;
2013-10-02 19:01:15 -07:00
AVAudioSession * audioSession = [ AVAudioSession sharedInstance ] ;
[ audioSession setCategory : AVAudioSessionCategoryPlayback
error : nil ] ;
2020-06-15 21:26:05 -07:00
WKWebViewConfiguration * configuration = [ WKWebViewConfiguration new ] ;
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
NSString * videoPlayback = [ preferences stringForKey : @ "video_playback" ] ;
configuration . allowsInlineMediaPlayback = ! [ videoPlayback isEqualToString : @ "fullscreen" ] ;
self . webView = [ [ WKWebView alloc ] initWithFrame : self . view . frame configuration : configuration ] ;
[ self . view addSubview : self . webView ] ;
self . webView . autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight ;
2020-02-23 15:21:32 -08:00
self . webView . navigationDelegate = self ;
2018-08-30 20:33:08 -07:00
self . webView . allowsLinkPreview = YES ;
2012-12-27 18:37:05 -08:00
2021-01-29 20:10:53 -08:00
[ self . webView . scrollView setAlwaysBounceVertical : appDelegate . storyPagesViewController . isHorizontal ] ;
2012-12-27 18:37:05 -08:00
[ self . webView . scrollView setDelaysContentTouches : NO ] ;
[ self . webView . scrollView setDecelerationRate : UIScrollViewDecelerationRateNormal ] ;
2020-03-29 16:21:00 -07:00
[ self . webView . scrollView setAutoresizingMask : ( UIViewAutoresizingFlexibleWidth |
2015-09-23 11:34:03 -07:00
UIViewAutoresizingFlexibleHeight ) ] ;
2018-11-29 13:35:44 -08:00
2020-09-25 20:31:01 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPad ) {
self . webView . scrollView . contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever ;
2018-11-29 13:35:44 -08:00
}
2013-03-22 19:25:41 -07:00
[ self . webView . scrollView addObserver : self forKeyPath : @ "contentOffset"
options : NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context : nil ] ;
2015-12-10 15:07:23 -08:00
2020-02-23 15:21:32 -08:00
[ self . appDelegate prepareWebView : self . webView completionHandler : nil ] ;
2020-06-15 21:26:05 -07:00
2015-12-10 15:07:23 -08:00
[ self clearWebView ] ;
2014-02-03 18:54:50 -08:00
2014-02-03 19:20:26 -08:00
UITapGestureRecognizer * doubleTapGesture = [ [ UITapGestureRecognizer alloc ]
2014-09-18 18:25:38 -07:00
initWithTarget : self action : @ selector ( doubleTap : ) ] ;
2014-02-03 19:20:26 -08:00
doubleTapGesture . numberOfTapsRequired = 2 ;
doubleTapGesture . delegate = self ;
2014-09-18 18:25:38 -07:00
[ self . webView addGestureRecognizer : doubleTapGesture ] ;
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
UITapGestureRecognizer * tapGesture = [ [ UITapGestureRecognizer alloc ]
initWithTarget : self action : @ selector ( tap : ) ] ;
tapGesture . numberOfTapsRequired = 1 ;
tapGesture . delegate = self ;
[ tapGesture requireGestureRecognizerToFail : doubleTapGesture ] ;
[ self . webView addGestureRecognizer : tapGesture ] ;
2014-02-03 19:20:26 -08:00
2014-02-05 17:14:23 -08:00
UITapGestureRecognizer * doubleDoubleTapGesture = [ [ UITapGestureRecognizer alloc ]
initWithTarget : self
2014-09-18 18:25:38 -07:00
action : @ selector ( doubleTap : ) ] ;
2014-02-05 17:14:23 -08:00
doubleDoubleTapGesture . numberOfTouchesRequired = 2 ;
doubleDoubleTapGesture . numberOfTapsRequired = 2 ;
doubleDoubleTapGesture . delegate = self ;
2014-09-18 18:25:38 -07:00
[ self . webView addGestureRecognizer : doubleDoubleTapGesture ] ;
2015-12-07 16:09:49 -08:00
2021-03-25 20:44:51 -07:00
UILongPressGestureRecognizer * longPressGesture = [ [ UILongPressGestureRecognizer alloc ]
initWithTarget : self
action : @ selector ( longPress : ) ] ;
longPressGesture . numberOfTouchesRequired = 1 ;
longPressGesture . delegate = self ;
[ self . webView addGestureRecognizer : longPressGesture ] ;
2020-08-25 21:46:23 -07:00
if ( [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone ) {
2019-03-04 20:07:42 -08:00
UIPinchGestureRecognizer * pinchGesture = [ [ UIPinchGestureRecognizer alloc ]
initWithTarget : self action : @ selector ( pinchGesture : ) ] ;
[ self . webView addGestureRecognizer : pinchGesture ] ;
}
2015-12-07 16:09:49 -08:00
[ [ ThemeManager themeManager ] addThemeGestureRecognizerToView : self . webView ] ;
2012-11-14 17:31:52 -08:00
self . pageIndex = -2 ;
2013-05-29 13:36:39 -07:00
self . inTextView = NO ;
2014-09-17 19:02:12 -07:00
2020-09-25 20:31:01 -07:00
_orientation = self . view . window . windowScene . interfaceOrientation ;
2011-08-24 10:24:02 -07:00
}
2014-02-03 19:20:26 -08:00
- ( BOOL ) gestureRecognizer : ( UIGestureRecognizer * ) gestureRecognizer shouldReceiveTouch : ( UITouch * ) touch {
2020-02-23 15:21:32 -08:00
// NSLog ( @ "%@: taps: %@, state: %@" , gestureRecognizer . class , @ ( touch . tapCount ) , @ ( gestureRecognizer . state ) ) ;
2016-02-01 10:44:59 -08:00
inDoubleTap = ( touch . tapCount = = 2 ) ;
CGPoint pt = [ self pointForGesture : gestureRecognizer ] ;
if ( pt . x = = CGPointZero . x && pt . y = = CGPointZero . y ) return YES ;
// NSLog ( @ "Tapped point: %@" , NSStringFromCGPoint ( pt ) ) ;
if ( inDoubleTap ) {
self . webView . scrollView . scrollEnabled = NO ;
[ self performSelector : @ selector ( deferredEnableScrolling ) withObject : nil afterDelay : 0.0 ] ;
}
2014-02-03 19:20:26 -08:00
return YES ;
}
2014-02-05 17:14:23 -08:00
2014-02-03 19:20:26 -08:00
- ( BOOL ) gestureRecognizer : ( UIGestureRecognizer * ) gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer : ( UIGestureRecognizer * ) otherGestureRecognizer {
2014-09-19 16:58:56 -07:00
// NSLog ( @ "Should conflict? \n\tgesture:%@ \n\t other:%@" ,
// gestureRecognizer , otherGestureRecognizer ) ;
2014-09-18 18:25:38 -07:00
return YES ;
}
- ( void ) tap : ( UITapGestureRecognizer * ) gestureRecognizer {
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
// NSLog ( @ "Gesture tap: %ld (%ld) - %d" , ( long ) gestureRecognizer . state , ( long ) UIGestureRecognizerStateEnded , inDoubleTap ) ;
2020-06-20 21:31:21 -07:00
if ( gestureRecognizer . state = = UIGestureRecognizerStateEnded && gestureRecognizer . numberOfTouches = = 1 && self . presentedViewController = = nil ) {
2019-02-28 15:29:31 -08:00
CGPoint pt = [ self pointForGesture : gestureRecognizer ] ;
if ( pt . x = = CGPointZero . x && pt . y = = CGPointZero . y ) return ;
2020-02-23 15:21:32 -08:00
if ( inDoubleTap ) return ;
2019-02-28 15:29:31 -08:00
// NSLog ( @ "Tapped point: %@" , NSStringFromCGPoint ( pt ) ) ;
2020-08-27 15:08:46 -07:00
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'tagName');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * tagName , NSError * error ) {
2020-02-23 15:21:32 -08:00
// Special case to handle the story title , Train , Save , and Share buttons .
2021-12-07 19:40:59 -07:00
if ( [ self isTag : tagName equalTo : @ "DIV" ] ) {
2020-08-27 15:08:46 -07:00
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'id');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * identifier , NSError * error ) {
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'outerHTML');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * outerHTML , NSError * error ) {
2020-02-23 15:21:32 -08:00
if ( [ identifier isEqualToString : @ "NB-story" ] || ! [ outerHTML containsString : @ "NB-" ] ) {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController tappedStory ] ;
2020-02-23 15:21:32 -08:00
}
} ] ;
} ] ;
return ;
}
2019-02-28 15:29:31 -08:00
2020-02-23 15:21:32 -08:00
// Ignore links , videos , and iframes ( e . g . embedded YouTube videos ) .
if ( ! [ @ [ @ "A" , @ "VIDEO" , @ "IFRAME" ] containsObject : tagName ] ) {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController tappedStory ] ;
2019-02-28 15:29:31 -08:00
}
2020-02-23 15:21:32 -08:00
} ] ;
2019-02-28 15:29:31 -08:00
}
2014-09-18 18:25:38 -07:00
}
- ( void ) doubleTap : ( UITapGestureRecognizer * ) gestureRecognizer {
2016-02-01 10:44:59 -08:00
// NSLog ( @ "Gesture double tap: %d (%d) - %d" , gestureRecognizer . state , UIGestureRecognizerStateEnded , inDoubleTap ) ;
if ( gestureRecognizer . state = = UIGestureRecognizerStateEnded && inDoubleTap ) {
2014-03-03 15:47:24 -08:00
NSUserDefaults * preferences = [ NSUserDefaults standardUserDefaults ] ;
BOOL openOriginal = NO ;
BOOL showText = NO ;
2014-03-03 16:21:26 -08:00
BOOL markUnread = NO ;
BOOL saveStory = NO ;
2014-02-05 17:14:23 -08:00
if ( gestureRecognizer . numberOfTouches = = 2 ) {
2014-03-03 15:47:24 -08:00
NSString * twoFingerTap = [ preferences stringForKey : @ "two_finger_double_tap" ] ;
if ( [ twoFingerTap isEqualToString : @ "open_original_story" ] ) {
openOriginal = YES ;
} else if ( [ twoFingerTap isEqualToString : @ "show_original_text" ] ) {
showText = YES ;
2014-03-03 16:21:26 -08:00
} else if ( [ twoFingerTap isEqualToString : @ "mark_unread" ] ) {
markUnread = YES ;
} else if ( [ twoFingerTap isEqualToString : @ "save_story" ] ) {
saveStory = YES ;
2014-03-03 15:47:24 -08:00
}
2014-02-05 17:14:23 -08:00
} else {
2014-03-03 15:47:24 -08:00
NSString * doubleTap = [ preferences stringForKey : @ "double_tap_story" ] ;
if ( [ doubleTap isEqualToString : @ "open_original_story" ] ) {
openOriginal = YES ;
} else if ( [ doubleTap isEqualToString : @ "show_original_text" ] ) {
showText = YES ;
2014-03-03 16:21:26 -08:00
} else if ( [ doubleTap isEqualToString : @ "mark_unread" ] ) {
markUnread = YES ;
} else if ( [ doubleTap isEqualToString : @ "save_story" ] ) {
saveStory = YES ;
2014-03-03 15:47:24 -08:00
}
}
if ( openOriginal ) {
2014-02-05 17:14:23 -08:00
[ self showOriginalStory : gestureRecognizer ] ;
2014-03-03 15:47:24 -08:00
} else if ( showText ) {
[ self fetchTextView ] ;
2014-03-03 16:21:26 -08:00
} else if ( markUnread ) {
2016-02-01 10:44:59 -08:00
[ appDelegate . storiesCollection toggleStoryUnread ] ;
2022-09-02 20:39:00 -06:00
[ appDelegate . feedDetailViewController reloadWithSizing ] ;
2014-03-03 16:21:26 -08:00
} else if ( saveStory ) {
2016-02-01 10:44:59 -08:00
[ appDelegate . storiesCollection toggleStorySaved ] ;
2022-09-02 20:39:00 -06:00
[ appDelegate . feedDetailViewController reloadWithSizing ] ;
2014-02-05 17:14:23 -08:00
}
2016-02-01 10:44:59 -08:00
inDoubleTap = NO ;
2015-11-12 15:30:40 -08:00
[ self performSelector : @ selector ( deferredEnableScrolling ) withObject : nil afterDelay : 0.0 ] ;
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . autoscrollActive = NO ;
2014-02-04 12:40:46 -08:00
}
2014-02-03 19:20:26 -08:00
}
2021-03-25 20:44:51 -07:00
- ( void ) longPress : ( UILongPressGestureRecognizer * ) gestureRecognizer {
if ( gestureRecognizer . state = = UIGestureRecognizerStateBegan ) {
CGPoint pt = [ self pointForGesture : gestureRecognizer ] ;
if ( pt . x = = CGPointZero . x && pt . y = = CGPointZero . y ) return ;
if ( inDoubleTap ) return ;
[ webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'tagName');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * tagName , NSError * error ) {
2021-12-07 19:40:59 -07:00
if ( [ self isTag : tagName equalTo : @ "IMG" ] ) {
2021-03-25 20:44:51 -07:00
[ self showImageMenu : pt ] ;
}
} ] ;
}
}
2019-03-04 20:07:42 -08:00
- ( void ) pinchGesture : ( UIPinchGestureRecognizer * ) gestureRecognizer {
if ( gestureRecognizer . state ! = UIGestureRecognizerStateEnded ) {
return ;
}
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . forceNavigationBarShown = gestureRecognizer . scale < 1 ;
[ appDelegate . storyPagesViewController changedFullscreen ] ;
2019-03-04 20:07:42 -08:00
}
2018-11-21 14:40:29 -08:00
- ( void ) screenEdgeSwipe : ( UITapGestureRecognizer * ) gestureRecognizer {
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
BOOL swipeEnabled = [ [ userPreferences stringForKey : @ "story_detail_swipe_left_edge" ]
isEqualToString : @ "pop_to_story_list" ] ;
2019-01-16 19:15:07 -08:00
if ( swipeEnabled && gestureRecognizer . state = = UIGestureRecognizerStateEnded ) {
[ appDelegate hideStoryDetailView ] ;
}
2018-11-21 14:40:29 -08:00
}
2015-11-12 15:30:40 -08:00
- ( void ) deferredEnableScrolling {
2023-03-30 10:36:31 -07:00
self . webView . scrollView . scrollEnabled = self . appDelegate . detailViewController . isPhone || ! self . appDelegate . detailViewController . storyTitlesInGrid ;
2015-11-12 15:30:40 -08:00
}
2011-08-14 10:22:26 -07:00
- ( void ) viewDidDisappear : ( BOOL ) animated {
2014-09-18 11:25:51 -07:00
[ super viewDidDisappear : animated ] ;
2015-11-05 14:16:11 -08:00
2016-02-01 10:44:59 -08:00
if ( ! appDelegate . showingSafariViewController &&
2020-08-29 21:19:32 -07:00
appDelegate . feedsNavigationController . visibleViewController ! = ( UIViewController * ) appDelegate . shareViewController &&
appDelegate . feedsNavigationController . visibleViewController ! = ( UIViewController * ) appDelegate . trainerViewController &&
appDelegate . feedsNavigationController . visibleViewController ! = ( UIViewController * ) appDelegate . originalStoryViewController ) {
2015-11-05 14:16:11 -08:00
[ self clearStory ] ;
}
2011-08-14 10:22:26 -07:00
}
2014-12-02 18:36:38 -08:00
- ( void ) viewWillDisappear : ( BOOL ) animated {
[ super viewWillDisappear : animated ] ;
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact ) {
2016-02-01 10:44:59 -08:00
[ appDelegate . feedDetailViewController . view endEditing : YES ] ;
2014-12-02 18:36:38 -08:00
}
2015-09-17 13:15:10 -07:00
[ self storeScrollPosition : NO ] ;
2019-01-30 15:07:26 -08:00
2019-06-25 20:53:54 -07:00
self . fullStoryHTML = nil ;
2014-12-02 18:36:38 -08:00
}
- ( void ) viewWillAppear : ( BOOL ) animated {
[ super viewWillAppear : animated ] ;
2016-10-05 21:03:32 -07:00
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact ) {
2016-02-01 10:44:59 -08:00
[ appDelegate . feedDetailViewController . view endEditing : YES ] ;
2014-12-02 18:36:38 -08:00
}
2020-09-25 20:31:01 -07:00
if ( _orientation ! = self . view . window . windowScene . interfaceOrientation ) {
_orientation = self . view . window . windowScene . interfaceOrientation ;
2015-09-23 14:37:54 -07:00
NSLog ( @ "Found stale orientation in story detail: %@" , NSStringFromCGSize ( self . view . bounds . size ) ) ;
}
2015-10-27 21:52:11 -07:00
2015-12-12 15:42:39 -08:00
if ( ! self . hasStory ) {
2015-10-27 21:52:11 -07:00
[ self drawStory ] ;
}
2015-09-23 14:37:54 -07:00
}
2015-09-28 20:01:17 -07:00
- ( void ) viewDidAppear : ( BOOL ) animated {
[ super viewDidAppear : animated ] ;
2015-10-24 20:58:00 -07:00
// Fix the position and size ; can probably remove this once all views use auto layout
CGRect viewFrame = self . view . frame ;
CGSize superSize = self . view . superview . bounds . size ;
if ( viewFrame . size . height > superSize . height ) {
self . view . frame = CGRectMake ( viewFrame . origin . x , viewFrame . origin . y , viewFrame . size . width , superSize . height ) ;
}
2015-09-28 20:01:17 -07:00
}
2015-09-22 13:10:35 -07:00
- ( void ) viewWillTransitionToSize : ( CGSize ) size withTransitionCoordinator : ( id < UIViewControllerTransitionCoordinator > ) coordinator {
2015-09-23 14:37:54 -07:00
[ super viewWillTransitionToSize : size withTransitionCoordinator : coordinator ] ;
2016-02-01 10:44:59 -08:00
scrollPct = self . webView . scrollView . contentOffset . y / self . webView . scrollView . contentSize . height ;
// NSLog ( @ "Current scroll is %2.2f%% (offset %.0f - height %.0f)" , scrollPct * 100 , self . webView . scrollView . contentOffset . y ,
2015-11-30 18:12:10 -08:00
// self . webView . scrollView . contentSize . height ) ;
2015-09-28 20:01:17 -07:00
2015-09-22 13:10:35 -07:00
[ coordinator animateAlongsideTransition : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
2020-09-25 20:31:01 -07:00
self -> _orientation = self . view . window . windowScene . interfaceOrientation ;
2015-09-22 13:10:35 -07:00
[ self changeWebViewWidth ] ;
[ self drawFeedGradient ] ;
2015-09-28 20:01:17 -07:00
[ self scrollToLastPosition : NO ] ;
2015-09-22 13:10:35 -07:00
} completion : ^ ( id < UIViewControllerTransitionCoordinatorContext > _Nonnull context ) {
} ] ;
}
2015-09-28 20:01:17 -07:00
- ( void ) viewWillLayoutSubviews {
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2015-09-28 20:01:17 -07:00
[ super viewWillLayoutSubviews ] ;
2017-04-11 15:43:42 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController layoutForInterfaceOrientation : orientation ] ;
2017-04-11 15:43:42 -07:00
[ self changeWebViewWidth ] ;
[ self drawFeedGradient ] ;
} ) ;
2015-11-30 18:12:10 -08:00
2015-12-01 16:51:18 -08:00
// NSLog ( @ "viewWillLayoutSubviews: %.2f" , self . webView . scrollView . bounds . size . width ) ;
2015-09-28 20:01:17 -07:00
}
2015-11-30 18:12:10 -08:00
- ( void ) layoutForInterfaceOrientation : ( UIInterfaceOrientation ) interfaceOrientation {
2016-02-01 10:44:59 -08:00
if ( interfaceOrientation ! = _orientation ) {
_orientation = interfaceOrientation ;
2015-11-30 18:12:10 -08:00
[ self changeWebViewWidth ] ;
[ self drawFeedGradient ] ;
[ self drawStory ] ;
}
2015-09-28 20:01:17 -07:00
}
2015-11-28 22:07:38 -08:00
- ( BOOL ) isPhoneOrCompact {
2020-08-25 21:46:23 -07:00
return [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone || self . appDelegate . isCompactWidth ;
2015-11-28 22:07:38 -08:00
}
2021-06-05 21:50:57 -07:00
// allow keyboard commands
2015-11-21 23:23:37 -05:00
- ( BOOL ) canBecomeFirstResponder {
return YES ;
}
2011-12-01 09:01:18 -08:00
# pragma mark -
2012-11-08 17:39:32 -08:00
# pragma mark Story setup
2012-11-06 12:45:19 -08:00
- ( void ) initStory {
2016-02-01 10:44:59 -08:00
appDelegate . inStoryDetail = YES ;
2013-09-26 19:26:10 -07:00
self . noStoryMessage . hidden = YES ;
2015-10-05 11:45:33 -07:00
self . inTextView = NO ;
2012-11-08 17:39:32 -08:00
2016-02-01 10:44:59 -08:00
[ appDelegate hideShareView : NO ] ;
2012-11-08 17:39:32 -08:00
}
2016-08-23 20:52:34 -04:00
- ( void ) loadHTMLString : ( NSString * ) html {
static NSURL * baseURL ;
static dispatch_once _t onceToken ;
dispatch_once ( & onceToken , ^ {
baseURL = [ NSBundle mainBundle ] . bundleURL ;
} ) ;
[ self . webView loadHTMLString : html baseURL : baseURL ] ;
}
2013-09-12 21:26:38 -07:00
- ( void ) hideNoStoryMessage {
2013-09-26 19:26:10 -07:00
self . noStoryMessage . hidden = YES ;
2013-09-12 21:26:38 -07:00
}
2012-11-08 17:39:32 -08:00
- ( void ) drawStory {
2020-09-25 20:31:01 -07:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2013-03-04 17:15:50 -08:00
[ self drawStory : NO withOrientation : orientation ] ;
}
- ( void ) drawStory : ( BOOL ) force withOrientation : ( UIInterfaceOrientation ) orientation {
2015-10-06 18:52:58 -07:00
if ( ! force && [ self . activeStoryId isEqualToString : [ self . activeStory objectForKey : @ "story_hash" ] ] ) {
2015-12-01 16:51:18 -08:00
// NSLog ( @ "Already drawn story, drawing anyway: %@" , [ self . activeStory objectForKey : @ "story_title" ] ) ;
2012-11-14 17:31:52 -08:00
// return ;
}
2019-03-22 20:55:22 -07:00
if ( self . activeStory = = nil ) {
return ;
}
2015-03-10 18:58:23 -07:00
2016-02-01 10:44:59 -08:00
scrollPct = 0 ;
hasScrolled = NO ;
2014-12-01 17:22:40 -08:00
2023-03-03 21:38:55 -07:00
if ( appDelegate . storyPagesViewController . currentPage = = self ) {
self . appDelegate . feedDetailViewController . storyHeight = 200 ;
}
2012-11-06 12:45:19 -08:00
NSString * shareBarString = [ self getShareBar ] ;
NSString * commentString = [ self getComments ] ;
NSString * headerString ;
NSString * sharingHtmlString ;
NSString * footerString ;
NSString * fontStyleClass = @ "" ;
2015-11-03 12:10:28 -08:00
NSString * customStyle = @ "" ;
2013-11-23 13:03:14 -08:00
NSString * fontSizeClass = @ "NB-" ;
2014-05-15 18:06:56 -07:00
NSString * lineSpacingClass = @ "NB-line-spacing-" ;
2017-11-15 17:11:37 -08:00
NSString * premiumOnlyClass = ( self . inTextView && ! appDelegate . isPremium ) ? @ "NB-premium-only" : @ "" ;
2013-06-23 22:19:08 -07:00
NSString * storyContent = [ self . activeStory objectForKey : @ "story_content" ] ;
2015-03-10 18:58:23 -07:00
if ( self . inTextView && [ self . activeStory objectForKey : @ "original_text" ] ) {
storyContent = [ self . activeStory objectForKey : @ "original_text" ] ;
}
2019-06-19 20:45:30 -07:00
NSString * changes = self . activeStory [ @ "story_changes" ] ;
if ( changes ! = nil ) {
storyContent = changes ;
}
2012-11-06 12:45:19 -08:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2015-11-02 22:17:06 -08:00
2017-11-15 17:11:37 -08:00
NSString * premiumTextString = [ NSString stringWithFormat : @ "<div class=\" NB - feed - story - premium - only - divider \ "></div>"
2017-11-15 17:11:44 -08:00
"<div class=\" NB - feed - story - premium - only - text \ ">The full Text view is a <a href=\" http : // ios . newsblur . com / premium \ ">premium feature</a></div>" ] ;
2017-11-15 17:11:37 -08:00
2015-11-03 12:10:28 -08:00
fontStyleClass = [ userPreferences stringForKey : @ "fontStyle" ] ;
if ( ! fontStyleClass ) {
2017-04-11 17:36:10 -07:00
fontStyleClass = @ "GothamNarrow-Book" ;
2012-11-06 12:45:19 -08:00
}
2015-11-03 12:10:28 -08:00
2013-11-23 13:03:14 -08:00
fontSizeClass = [ fontSizeClass stringByAppendingString : [ userPreferences stringForKey : @ "story_font_size" ] ] ;
2012-11-06 12:45:19 -08:00
2015-11-03 12:10:28 -08:00
if ( ! [ fontStyleClass hasPrefix : @ "NB-" ] ) {
customStyle = [ NSString stringWithFormat : @ " style='font-family: %@;'" , fontStyleClass ] ;
2015-11-02 22:17:06 -08:00
}
2014-05-15 18:06:56 -07:00
if ( [ userPreferences stringForKey : @ "story_line_spacing" ] ) {
lineSpacingClass = [ lineSpacingClass stringByAppendingString : [ userPreferences stringForKey : @ "story_line_spacing" ] ] ;
} else {
lineSpacingClass = [ lineSpacingClass stringByAppendingString : @ "medium" ] ;
}
2015-09-28 20:01:17 -07:00
int contentWidth = CGRectGetWidth ( self . webView . scrollView . bounds ) ;
2012-11-06 12:45:19 -08:00
NSString * contentWidthClass ;
2015-12-01 16:51:18 -08:00
// NSLog ( @ "Drawing story: %@ / %d" , [ self . activeStory objectForKey : @ "story_title" ] , contentWidth ) ;
2012-11-06 12:45:19 -08:00
2020-03-29 16:21:00 -07:00
# if TARGET_OS _MACCATALYST
// CATALYST : probably will want to add custom CSS for Macs .
contentWidthClass = @ "NB-ipad-wide NB-ipad-pro-12-wide NB-width-768" ;
# else
2015-11-28 22:07:38 -08:00
if ( UIInterfaceOrientationIsLandscape ( orientation ) && ! self . isPhoneOrCompact ) {
2017-11-01 21:51:56 -07:00
if ( iPadPro12 ) {
contentWidthClass = @ "NB-ipad-wide NB-ipad-pro-12-wide" ;
} else if ( iPadPro10 ) {
contentWidthClass = @ "NB-ipad-wide NB-ipad-pro-10-wide" ;
2016-04-06 18:14:06 -07:00
} else {
contentWidthClass = @ "NB-ipad-wide" ;
}
2015-11-28 22:07:38 -08:00
} else if ( ! UIInterfaceOrientationIsLandscape ( orientation ) && ! self . isPhoneOrCompact ) {
2017-11-01 21:51:56 -07:00
if ( iPadPro12 ) {
contentWidthClass = @ "NB-ipad-narrow NB-ipad-pro-12-narrow" ;
} else if ( iPadPro10 ) {
contentWidthClass = @ "NB-ipad-narrow NB-ipad-pro-10-narrow" ;
2016-04-06 18:14:06 -07:00
} else {
contentWidthClass = @ "NB-ipad-narrow" ;
}
2015-11-28 22:07:38 -08:00
} else if ( UIInterfaceOrientationIsLandscape ( orientation ) && self . isPhoneOrCompact ) {
2014-09-19 17:25:57 -07:00
contentWidthClass = @ "NB-iphone-wide" ;
2012-11-06 12:45:19 -08:00
} else {
contentWidthClass = @ "NB-iphone" ;
}
2014-09-24 12:00:47 -07:00
contentWidthClass = [ NSString stringWithFormat : @ "%@ NB-width-%d" ,
contentWidthClass , ( int ) floorf ( CGRectGetWidth ( self . view . frame ) ) ] ;
2020-03-29 16:21:00 -07:00
# endif
2014-09-24 12:00:47 -07:00
2023-06-15 15:24:13 -07:00
if ( appDelegate . feedsViewController . isOffline ) {
NSString * storyHash = [ self . activeStory objectForKey : @ "story_hash" ] ;
NSArray * imageUrls = [ appDelegate . activeCachedImages objectForKey : storyHash ] ;
if ( imageUrls ) {
2023-07-04 15:23:01 -07:00
NSString * storyImagesDirectory = [ appDelegate . documentsURL . path
2023-06-15 15:24:13 -07:00
stringByAppendingPathComponent : @ "story_images" ] ;
for ( NSString * imageUrl in imageUrls ) {
NSURL * cachedUrl = [ NSURL fileURLWithPath : storyImagesDirectory ] ;
cachedUrl = [ cachedUrl URLByAppendingPathComponent : [ Utilities md5 : imageUrl ] ] ;
cachedUrl = [ cachedUrl URLByAppendingPathExtension : imageUrl . pathExtension ] ;
storyContent = [ storyContent
stringByReplacingOccurrencesOfString : imageUrl
withString : cachedUrl . absoluteString ] ;
}
}
}
2020-06-29 16:25:27 -07:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" ,
[ self . activeStory
objectForKey : @ "story_feed_id" ] ] ;
NSDictionary * feed = [ appDelegate getFeed : feedIdStr ] ;
2020-06-29 15:20:08 -07:00
NSString * storyClassSuffix = @ "" ;
2020-09-28 12:44:07 -04:00
if ( [ feed [ @ "is_newsletter" ] isEqualToNumber : [ NSNumber numberWithInt : 1 ] ] ) {
2020-06-29 15:20:08 -07:00
storyClassSuffix = @ " NB-newsletter" ;
}
2016-02-01 10:44:59 -08:00
NSString * riverClass = ( appDelegate . storiesCollection . isRiverView ||
appDelegate . storiesCollection . isSocialView ||
appDelegate . storiesCollection . isSavedView ||
2022-03-09 19:16:43 -07:00
appDelegate . storiesCollection . isWidgetView ||
2016-02-01 10:44:59 -08:00
appDelegate . storiesCollection . isReadView ) ?
2013-03-06 14:29:40 -08:00
@ "NB-river" : @ "NB-non-river" ;
2018-10-22 15:14:12 -07:00
NSString * themeStyle = [ NSString stringWithFormat : @ "<link rel=\" stylesheet \ " type=\" text / css \ " id=\" NB - theme - style \ " href=\" storyDetailView % @ . css \ ">" , [ ThemeManager themeManager ] . themeCSSSuffix ] ;
2015-12-07 16:09:49 -08:00
2012-11-06 12:45:19 -08:00
// set up layout values based on iPad / iPhone
headerString = [ NSString stringWithFormat : @
2015-12-07 16:09:49 -08:00
"<link rel=\" stylesheet \ " type=\" text / css \ " href=\" storyDetailView . css \ ">%@"
2015-09-22 13:10:35 -07:00
"<meta name=\" viewport \ " id=\" viewport \ " content=\" width = % d , initial - scale = 1.0 , minimum - scale = 1.0 , maximum - scale = 1.0 , user - scalable = no \ "/>" ,
2015-12-07 16:09:49 -08:00
themeStyle , contentWidth ] ;
2012-11-06 12:45:19 -08:00
footerString = [ NSString stringWithFormat : @
"<script src=\" zepto . js \ "></script>"
2014-01-06 15:02:12 -08:00
"<script src=\" fitvid . js \ "></script>"
2012-12-25 19:03:50 -08:00
"<script src=\" storyDetailView . js \ "></script>"
"<script src=\" fastTouch . js \ "></script>" ] ;
2012-11-06 12:45:19 -08:00
2020-10-30 20:58:27 -07:00
sharingHtmlString = [ self getSideOptions ] ;
2012-12-07 17:18:31 -08:00
NSString * storyHeader = [ self getHeader ] ;
2016-02-05 12:19:48 -08:00
NSString * htmlTop = [ NSString stringWithFormat : @
2016-01-21 14:01:25 -08:00
"<!DOCTYPE html>\n"
2012-11-06 12:45:19 -08:00
"<html>"
"<head>%@</head>" // header string
2013-03-06 14:29:40 -08:00
"<body id=\" story_pane \ " class=\" % @ % @ \ ">"
2017-11-15 17:11:37 -08:00
" <div class=\" % @ \ " id=\" NB - premium - check \ ">"
2015-11-02 22:17:06 -08:00
" <div class=\" % @ \ " id=\" NB - font - style \ "%@>"
2014-05-15 18:06:56 -07:00
" <div class=\" % @ \ " id=\" NB - font - size \ ">"
" <div class=\" % @ \ " id=\" NB - line - spacing \ ">"
" <div id=\" NB - header - container \ ">%@</div>" // storyHeader
2016-02-05 12:19:48 -08:00
" %@" , // shareBar
2012-11-06 12:45:19 -08:00
headerString ,
contentWidthClass ,
2013-03-06 14:29:40 -08:00
riverClass ,
2017-11-15 17:11:37 -08:00
premiumOnlyClass ,
2012-11-06 12:45:19 -08:00
fontStyleClass ,
2015-11-02 22:17:06 -08:00
customStyle ,
2012-11-06 12:45:19 -08:00
fontSizeClass ,
2014-05-15 18:06:56 -07:00
lineSpacingClass ,
2012-12-11 17:53:17 -08:00
storyHeader ,
2016-02-05 12:19:48 -08:00
shareBarString
] ;
NSString * htmlBottom = [ NSString stringWithFormat : @
" </div>" // line - spacing
" </div>" // font - size
" </div>" // font - style
2017-11-15 17:11:37 -08:00
" </div>" // premium check
2016-02-05 12:19:48 -08:00
"</body>"
"</html>"
2012-11-06 12:45:19 -08:00
] ;
2016-02-05 12:19:48 -08:00
NSString * htmlContent = [ NSString stringWithFormat : @
"%@" // header
2020-06-29 15:20:08 -07:00
" <div id=\" NB - story \ " class=\" NB - story % @ \ ">%@</div>"
2017-11-15 17:11:37 -08:00
" <div class=\" NB - text - view - premium - only \ ">%@</div>"
2016-02-05 12:19:48 -08:00
" <div id=\" NB - sideoptions - container \ ">%@</div>"
" <div id=\" NB - comments - wrapper \ ">"
" %@" // friends comments
" </div>"
" %@"
"%@" , // footer
htmlTop ,
2020-06-29 15:20:08 -07:00
storyClassSuffix ,
2016-02-05 12:19:48 -08:00
storyContent ,
2017-11-15 17:11:37 -08:00
premiumTextString ,
2016-02-05 12:19:48 -08:00
sharingHtmlString ,
commentString ,
footerString ,
htmlBottom
] ;
2016-08-23 20:52:34 -04:00
NSString * htmlTopAndBottom = [ htmlTop stringByAppendingString : htmlBottom ] ;
2016-02-05 12:19:48 -08:00
2016-02-27 13:20:32 -08:00
// NSLog ( @ "\n\n\n\nStory html (%@):\n\n\n%@\n\n\n" , self . activeStory [ @ "story_title" ] , htmlContent ) ;
2016-08-23 20:52:34 -04:00
self . hasStory = NO ;
self . fullStoryHTML = htmlContent ;
2016-02-05 12:19:48 -08:00
2023-10-18 16:14:46 -06:00
NSLog ( @ "📚 full story for: %@" , self . activeStory [ @ "story_title" ] ) ; // log
2015-10-02 16:04:49 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2015-12-01 16:51:18 -08:00
// NSLog ( @ "Drawing Story: %@" , [ self . activeStory objectForKey : @ "story_title" ] ) ;
2023-10-18 16:14:46 -06:00
NSLog ( @ "📚 %@ story: %@" , self . hasStory ? @ "has" : @ "hasn't" , self . activeStory [ @ "story_title" ] ) ; // log
2021-05-07 21:54:34 -07:00
if ( self . hasStory )
return ;
2016-08-23 20:52:34 -04:00
[ self loadHTMLString : htmlTopAndBottom ] ;
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController setTextButton : ( StoryDetailViewController * ) self ] ;
2023-10-18 16:14:46 -06:00
NSLog ( @ "📚 loaded top & bottom for: %@" , self . activeStory [ @ "story_title" ] ) ; // log
2015-10-02 16:04:49 -07:00
} ) ;
2019-06-25 20:53:54 -07:00
2021-05-07 21:54:34 -07:00
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , ( int64_t ) ( 1 * NSEC_PER _SEC ) ) , dispatch_get _main _queue ( ) , ^ {
2019-06-25 20:53:54 -07:00
[ self loadStory ] ;
} ) ;
2014-12-01 17:22:40 -08:00
self . activeStoryId = [ self . activeStory objectForKey : @ "story_hash" ] ;
2015-09-16 21:34:41 -07:00
}
2014-12-01 17:22:40 -08:00
- ( void ) drawFeedGradient {
2021-01-29 20:10:53 -08:00
BOOL shouldHideStatusBar = appDelegate . storyPagesViewController . shouldHideStatusBar ;
2020-07-31 16:10:09 -07:00
CGFloat yOffset = -1 ;
2012-11-06 12:45:19 -08:00
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" ,
[ self . activeStory
objectForKey : @ "story_feed_id" ] ] ;
2016-02-01 10:44:59 -08:00
NSDictionary * feed = [ appDelegate getFeed : feedIdStr ] ;
2012-11-06 12:45:19 -08:00
2022-03-28 20:38:20 -07:00
if ( appDelegate . storyPagesViewController . view . safeAreaInsets . top > 0.0 && appDelegate . storyPagesViewController . currentlyTogglingNavigationBar && ! appDelegate . storyPagesViewController . isNavigationBarHidden ) {
2020-07-31 16:10:09 -07:00
yOffset - = 25 ;
}
2015-09-28 20:01:17 -07:00
if ( self . feedTitleGradient ) {
[ self . feedTitleGradient removeFromSuperview ] ;
self . feedTitleGradient = nil ;
}
2016-02-01 10:44:59 -08:00
self . feedTitleGradient = [ appDelegate
2012-12-07 17:18:31 -08:00
makeFeedTitleGradient : feed
2021-03-27 17:46:34 -07:00
withRect : CGRectMake ( 0 , yOffset , CGRectGetWidth ( self . view . bounds ) , 25 ) ] ; // 1024 hack for self . webView . frame . size . width
2015-09-22 18:20:48 -07:00
self . feedTitleGradient . autoresizingMask = UIViewAutoresizingFlexibleWidth ;
2012-11-06 12:45:19 -08:00
self . feedTitleGradient . tag = FEED_TITLE _GRADIENT _TAG ; // Not attached yet . Remove old gradients , first .
for ( UIView * subview in self . webView . subviews ) {
if ( subview . tag = = FEED_TITLE _GRADIENT _TAG ) {
[ subview removeFromSuperview ] ;
}
}
2016-02-01 10:44:59 -08:00
if ( appDelegate . storiesCollection . isRiverView ||
appDelegate . storiesCollection . isSocialView ||
appDelegate . storiesCollection . isSavedView ||
2022-03-09 19:16:43 -07:00
appDelegate . storiesCollection . isWidgetView ||
2016-02-01 10:44:59 -08:00
appDelegate . storiesCollection . isReadView ) {
2021-03-27 17:46:34 -07:00
self . webView . scrollView . scrollIndicatorInsets = UIEdgeInsetsMake ( 24 , 0 , 0 , 0 ) ;
2012-11-06 12:45:19 -08:00
} else {
self . webView . scrollView . scrollIndicatorInsets = UIEdgeInsetsMake ( 9 , 0 , 0 , 0 ) ;
}
2016-02-01 10:44:59 -08:00
[ self . webView insertSubview : feedTitleGradient aboveSubview : self . webView . scrollView ] ;
2018-12-13 08:22:37 -08:00
2021-01-29 20:10:53 -08:00
if ( appDelegate . storyPagesViewController . view . safeAreaInsets . top > 0.0 && [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone && shouldHideStatusBar ) {
feedTitleGradient . alpha = appDelegate . storyPagesViewController . isNavigationBarHidden ? 1 : 0 ;
2020-09-25 20:31:01 -07:00
[ UIView animateWithDuration : 0.3 animations : ^ {
2021-01-29 20:10:53 -08:00
self . feedTitleGradient . alpha = self . appDelegate . storyPagesViewController . isNavigationBarHidden ? 0 : 1 ;
2020-09-25 20:31:01 -07:00
} ] ;
2018-12-13 08:22:37 -08:00
}
2012-11-06 12:45:19 -08:00
}
2012-11-08 17:39:32 -08:00
- ( void ) showStory {
2014-02-12 20:41:29 -08:00
id storyId = [ self . activeStory objectForKey : @ "story_hash" ] ;
2016-02-01 10:44:59 -08:00
[ appDelegate . storiesCollection pushReadStory : storyId ] ;
[ appDelegate resetShareComments ] ;
2012-11-08 17:39:32 -08:00
}
- ( void ) clearStory {
2012-11-14 17:31:52 -08:00
self . activeStoryId = nil ;
2015-10-06 18:52:58 -07:00
if ( self . activeStory ) self . activeStoryId = [ self . activeStory objectForKey : @ "story_hash" ] ;
2015-12-10 15:07:23 -08:00
[ self clearWebView ] ;
2013-10-17 11:21:37 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : NO ] ;
2012-11-08 17:39:32 -08:00
}
- ( void ) hideStory {
2012-11-14 17:31:52 -08:00
self . activeStoryId = nil ;
2012-11-08 17:39:32 -08:00
self . webView . hidden = YES ;
2013-09-26 19:26:10 -07:00
self . noStoryMessage . hidden = NO ;
2020-10-30 20:58:27 -07:00
[ self . activityIndicator stopAnimating ] ;
2021-03-25 18:22:34 -07:00
[ appDelegate . storyPagesViewController setTextButton ] ;
2012-11-08 17:39:32 -08:00
}
# pragma mark -
# pragma mark Story layout
2015-12-10 15:07:23 -08:00
- ( void ) clearWebView {
2015-12-12 15:42:39 -08:00
self . hasStory = NO ;
2016-01-07 21:12:58 -08:00
self . view . backgroundColor = UIColorFromRGB ( NEWSBLUR_WHITE _COLOR ) ;
self . webView . hidden = YES ;
self . activityIndicator . color = UIColorFromRGB ( NEWSBLUR_BLACK _COLOR ) ;
[ self . activityIndicator startAnimating ] ;
2015-12-10 15:07:23 -08:00
NSString * themeStyle = [ ThemeManager themeManager ] . themeCSSSuffix ;
if ( themeStyle . length ) {
themeStyle = [ NSString stringWithFormat : @ "<link rel=\" stylesheet \ " type=\" text / css \ " href=\" storyDetailView % @ . css \ ">" , themeStyle ] ;
}
NSString * html = [ NSString stringWithFormat : @ "<html>"
"<head><link rel=\" stylesheet \ " type=\" text / css \ " href=\" storyDetailView . css \ ">%@</head>" // header string
"<body></body>"
"</html>" , themeStyle ] ;
2016-08-23 20:52:34 -04:00
[ self loadHTMLString : html ] ;
2015-12-10 15:07:23 -08:00
}
2012-12-07 17:18:31 -08:00
- ( NSString * ) getHeader {
2012-12-19 15:37:36 -08:00
NSString * feedId = [ NSString stringWithFormat : @ "%@" , [ self . activeStory
2012-12-11 11:50:06 -08:00
objectForKey : @ "story_feed_id" ] ] ;
NSString * storyAuthor = @ "" ;
if ( [ [ self . activeStory objectForKey : @ "story_authors" ] class ] ! = [ NSNull class ] &&
[ [ self . activeStory objectForKey : @ "story_authors" ] length ] ) {
2012-12-07 17:18:31 -08:00
NSString * author = [ NSString stringWithFormat : @ "%@" ,
2016-03-07 22:46:34 -08:00
[ [ [ [ self . activeStory objectForKey : @ "story_authors" ] stringByReplacingOccurrencesOfString : @ "\" " withString:@" " ]
stringByReplacingOccurrencesOfString : @ "<" withString : @ "<" ]
stringByReplacingOccurrencesOfString : @ ">" withString : @ ">" ] ] ;
if ( author && author . length ) {
2016-02-01 10:44:59 -08:00
int authorScore = [ [ [ [ appDelegate . storiesCollection . activeClassifiers objectForKey : feedId ]
2012-12-11 11:50:06 -08:00
objectForKey : @ "authors" ]
objectForKey : author ] intValue ] ;
2013-03-05 10:39:15 -08:00
storyAuthor = [ NSString stringWithFormat : @ "<span class=\" NB - middot \ ">·</span><a href=\" http : // ios . newsblur . com / classify - author / % @ \ " "
2012-12-11 11:50:06 -08:00
"class=\" NB - story - author % @ \ " id=\" NB - story - author \ "><div class=\" NB - highlight \ "></div>%@</a>" ,
author ,
authorScore > 0 ? @ "NB-story-author-positive" : authorScore < 0 ? @ "NB-story-author-negative" : @ "" ,
author ] ;
2012-12-07 17:18:31 -08:00
}
}
2012-12-11 11:50:06 -08:00
NSString * storyTags = @ "" ;
2012-12-07 17:18:31 -08:00
if ( [ self . activeStory objectForKey : @ "story_tags" ] ) {
2012-12-11 11:50:06 -08:00
NSArray * tagArray = [ self . activeStory objectForKey : @ "story_tags" ] ;
if ( [ tagArray count ] > 0 ) {
NSMutableArray * tagStrings = [ NSMutableArray array ] ;
for ( NSString * tag in tagArray ) {
2016-02-01 10:44:59 -08:00
int tagScore = [ [ [ [ appDelegate . storiesCollection . activeClassifiers objectForKey : feedId ]
2012-12-11 11:50:06 -08:00
objectForKey : @ "tags" ]
objectForKey : tag ] intValue ] ;
NSString * tagHtml = [ NSString stringWithFormat : @ "<a href=\" http : // ios . newsblur . com / classify - tag / % @ \ " "
2013-08-05 17:29:42 -07:00
"class=\" NB - story - tag % @ \ "><div class=\" NB - highlight \ "></div>%@</a>" ,
tag ,
tagScore > 0 ? @ "NB-story-tag-positive" : tagScore < 0 ? @ "NB-story-tag-negative" : @ "" ,
tag ] ;
2012-12-11 11:50:06 -08:00
[ tagStrings addObject : tagHtml ] ;
2012-12-07 17:18:31 -08:00
}
2012-12-11 11:50:06 -08:00
storyTags = [ NSString
stringWithFormat : @ "<div id=\" NB - story - tags \ " class=\" NB - story - tags \ ">"
"%@"
"</div>" ,
[ tagStrings componentsJoinedByString : @ "" ] ] ;
2012-12-07 17:18:31 -08:00
}
}
2013-08-05 17:29:42 -07:00
NSString * storyStarred = @ "" ;
2014-11-04 17:13:53 -08:00
NSString * storyUserTags = @ "" ;
2014-11-10 18:25:31 -08:00
NSMutableArray * tagStrings = [ NSMutableArray array ] ;
2013-08-05 17:29:42 -07:00
if ( [ self . activeStory objectForKey : @ "starred" ] && [ self . activeStory objectForKey : @ "starred_date" ] ) {
2014-11-04 17:13:53 -08:00
storyStarred = [ NSString stringWithFormat : @ "<div class=\" NB - story - starred - date \ ">Saved on %@</div>" ,
2013-08-05 17:29:42 -07:00
[ self . activeStory objectForKey : @ "starred_date" ] ] ;
2014-11-04 17:13:53 -08:00
if ( [ self . activeStory objectForKey : @ "user_tags" ] ) {
NSArray * tagArray = [ self . activeStory objectForKey : @ "user_tags" ] ;
if ( [ tagArray count ] > 0 ) {
for ( NSString * tag in tagArray ) {
NSString * tagHtml = [ NSString stringWithFormat : @ "<a href=\" http : // ios . newsblur . com / remove - user - tag / % @ \ " "
"class=\" NB - user - tag \ "><div class=\" NB - highlight \ "></div>%@</a>" ,
tag ,
tag ] ;
[ tagStrings addObject : tagHtml ] ;
}
}
}
2014-11-10 18:25:31 -08:00
storyUserTags = [ NSString
stringWithFormat : @ "<div id=\" NB - user - tags \ " class=\" NB - user - tags \ ">"
"%@"
"<a class=\" NB - user - tag NB - add - user - tag \ " href=\" http : // ios . newsblur . com / add - user - tag / add - user - tag / \ "><div class=\" NB - highlight \ "></div>Add Tag</a>"
"</div>" ,
[ tagStrings componentsJoinedByString : @ "" ] ] ;
2013-08-05 17:29:42 -07:00
}
2012-12-07 17:18:31 -08:00
2013-10-04 12:37:51 -07:00
NSString * storyUnread = @ "" ;
2016-02-01 10:44:59 -08:00
if ( self . isRecentlyUnread && [ appDelegate . storiesCollection isStoryUnread : self . activeStory ] ) {
2013-10-04 12:37:51 -07:00
NSInteger score = [ NewsBlurAppDelegate computeStoryScore : [ self . activeStory objectForKey : @ "intelligence" ] ] ;
storyUnread = [ NSString stringWithFormat : @ "<div class=\" NB - story - unread NB - % @ \ "></div>" ,
score > 0 ? @ "positive" : score < 0 ? @ "negative" : @ "neutral" ] ;
}
2012-12-11 11:50:06 -08:00
NSString * storyTitle = [ self . activeStory objectForKey : @ "story_title" ] ;
2013-11-23 13:25:26 -08:00
NSString * storyPermalink = [ self . activeStory objectForKey : @ "story_permalink" ] ;
2016-02-01 10:44:59 -08:00
NSMutableDictionary * titleClassifiers = [ [ appDelegate . storiesCollection . activeClassifiers
2014-02-12 20:09:37 -08:00
objectForKey : feedId ]
objectForKey : @ "titles" ] ;
2012-12-11 11:50:06 -08:00
for ( NSString * titleClassifier in titleClassifiers ) {
if ( [ storyTitle containsString : titleClassifier ] ) {
int titleScore = [ [ titleClassifiers objectForKey : titleClassifier ] intValue ] ;
storyTitle = [ storyTitle
stringByReplacingOccurrencesOfString : titleClassifier
withString : [ NSString stringWithFormat : @ "<span class=\" NB - story - title - % @ \ ">%@</span>" ,
titleScore > 0 ? @ "positive" : titleScore < 0 ? @ "negative" : @ "" ,
titleClassifier ] ] ;
2012-12-07 17:18:31 -08:00
}
}
2019-06-19 20:45:30 -07:00
NSString * storyToggleChanges = [ self . activeStory [ @ "has_modifications" ] boolValue ] ? [ NSString stringWithFormat : @ "<a href=\" http : // ios . newsblur . com / togglechanges \ " "
"class=\" NB - story - toggle - changes \ " id=\" NB - story - toggle - changes \ ">%@</a><span class=\" NB - middot \ ">·</span>" , self . activeStory [ @ "story_changes" ] ! = nil ? @ "Hide Changes" : @ "Show Changes" ] : @ "" ;
2013-10-10 12:58:40 -07:00
NSString * storyDate = [ Utilities formatLongDateFromTimestamp : [ [ self . activeStory
objectForKey : @ "story_timestamp" ]
integerValue ] ] ;
2012-12-07 17:18:31 -08:00
NSString * storyHeader = [ NSString stringWithFormat : @
"<div class=\" NB - header \ "><div class=\" NB - header - inner \ ">"
2013-10-04 12:37:51 -07:00
"<div class=\" NB - story - title \ ">"
" %@"
2013-11-23 13:25:26 -08:00
" <a href=\" % @ \ " class=\" NB - story - permalink \ ">%@</a>"
2013-10-04 12:37:51 -07:00
"</div>"
2019-06-19 20:45:30 -07:00
"%@"
2013-03-05 10:39:15 -08:00
"<div class=\" NB - story - date \ ">%@</div>"
2012-12-07 17:18:31 -08:00
"%@"
"%@"
2013-08-05 17:29:42 -07:00
"%@"
2014-11-04 17:13:53 -08:00
"%@"
2012-12-07 17:18:31 -08:00
"</div></div>" ,
2013-10-04 12:37:51 -07:00
storyUnread ,
2013-11-23 13:25:26 -08:00
storyPermalink ,
2012-12-11 11:50:06 -08:00
storyTitle ,
2019-06-19 20:45:30 -07:00
storyToggleChanges ,
2013-10-10 12:58:40 -07:00
storyDate ,
2012-12-11 11:50:06 -08:00
storyAuthor ,
2013-08-05 17:29:42 -07:00
storyTags ,
2014-11-04 17:13:53 -08:00
storyStarred ,
storyUserTags ] ;
2012-12-07 17:18:31 -08:00
return storyHeader ;
}
2020-10-30 20:58:27 -07:00
- ( NSString * ) getSideOptions {
2014-05-21 12:24:22 -07:00
BOOL isSaved = [ [ self . activeStory objectForKey : @ "starred" ] boolValue ] ;
BOOL isShared = [ [ self . activeStory objectForKey : @ "shared" ] boolValue ] ;
2020-10-30 20:58:27 -07:00
NSString * sideOptions = [ NSString stringWithFormat : @
2014-05-21 12:24:22 -07:00
"<div class='NB-sideoptions'>"
"<div class='NB-share-header'></div>"
"<div class='NB-share-wrapper'><div class='NB-share-inner-wrapper'>"
" <div id=\" NB - share - button - id \ " class='NB-share-button NB-train-button NB-button'>"
" <a href=\" http : // ios . newsblur . com / train \ "><div>"
2022-08-05 10:08:57 -04:00
" <span class=\" NB - icon \ "></span>"
" <span class=\" NB - sideoption - text \ ">Train</span>"
2014-05-21 12:24:22 -07:00
" </div></a>"
" </div>"
" <div id=\" NB - share - button - id \ " class='NB-share-button NB-button %@'>"
" <a href=\" http : // ios . newsblur . com / share \ "><div>"
2022-08-05 10:08:57 -04:00
" <span class=\" NB - icon \ "></span>"
" <span class=\" NB - sideoption - text \ ">%@</span>"
2014-05-21 12:24:22 -07:00
" </div></a>"
" </div>"
" <div id=\" NB - share - button - id \ " class='NB-share-button NB-save-button NB-button %@'>"
2014-12-16 15:36:58 -08:00
" <a href=\" http : // ios . newsblur . com / save / save / \ "><div>"
2022-08-05 10:08:57 -04:00
" <span class=\" NB - icon \ "></span>"
" <span class=\" NB - sideoption - text \ ">%@</span>"
2014-05-21 12:24:22 -07:00
" </div></a>"
" </div>"
"</div></div></div>" ,
isShared ? @ "NB-button-active" : @ "" ,
isShared ? @ "Shared" : @ "Share" ,
isSaved ? @ "NB-button-active" : @ "" ,
isSaved ? @ "Saved" : @ "Save"
] ;
2020-10-30 20:58:27 -07:00
return sideOptions ;
2014-05-21 12:24:22 -07:00
}
2012-08-10 09:45:44 -07:00
- ( NSString * ) getAvatars : ( NSString * ) key {
2012-06-24 18:17:22 -07:00
NSString * avatarString = @ "" ;
2012-12-11 11:50:06 -08:00
NSArray * shareUserIds = [ self . activeStory objectForKey : key ] ;
2012-06-24 18:17:22 -07:00
2012-12-11 11:50:06 -08:00
for ( int i = 0 ; i < shareUserIds . count ; i + + ) {
2016-02-01 10:44:59 -08:00
NSDictionary * user = [ appDelegate getUser : [ [ shareUserIds objectAtIndex : i ] intValue ] ] ;
2012-08-13 15:34:53 -07:00
NSString * avatarClass = @ "NB-user-avatar" ;
if ( [ key isEqualToString : @ "commented_by_public" ] ||
[ key isEqualToString : @ "shared_by_public" ] ) {
avatarClass = @ "NB-public-user NB-user-avatar" ;
}
2012-06-24 18:17:22 -07:00
NSString * avatar = [ NSString stringWithFormat : @
2012-08-13 15:34:53 -07:00
"<div class=\" NB - story - share - profile \ "><div class=\" % @ \ ">"
2012-12-07 17:18:31 -08:00
"<a id=\" NB - user - share - bar - % @ \ " class=\" NB - show - profile \ " "
2012-12-11 11:50:06 -08:00
" href=\" http : // ios . newsblur . com / show - profile / % @ \ ">"
"<div class=\" NB - highlight \ "></div>"
"<img src=\" % @ \ " />"
"</a>"
2012-06-24 18:17:22 -07:00
"</div></div>" ,
2012-08-13 15:34:53 -07:00
avatarClass ,
2012-07-01 21:58:55 -07:00
[ user objectForKey : @ "user_id" ] ,
2012-08-01 12:41:02 -07:00
[ user objectForKey : @ "user_id" ] ,
2012-07-11 10:33:39 -07:00
[ user objectForKey : @ "photo_url" ] ] ;
2012-06-24 18:17:22 -07:00
avatarString = [ avatarString stringByAppendingString : avatar ] ;
}
2012-08-10 09:45:44 -07:00
2012-06-24 18:17:22 -07:00
return avatarString ;
}
2012-08-07 11:27:00 -07:00
- ( NSString * ) getComments {
2015-09-16 20:24:11 -07:00
NSString * comments = @ "" ;
2012-07-27 12:27:13 -07:00
2015-09-16 20:24:11 -07:00
if ( [ self . activeStory objectForKey : @ "share_count" ] ! = [ NSNull null ] &&
[ [ self . activeStory objectForKey : @ "share_count" ] intValue ] > 0 ) {
2012-11-05 17:16:10 -08:00
NSDictionary * story = self . activeStory ;
2012-07-20 00:21:24 -07:00
NSArray * friendsCommentsArray = [ story objectForKey : @ "friend_comments" ] ;
2015-09-07 21:39:51 -07:00
NSArray * friendsShareArray = [ story objectForKey : @ "friend_shares" ] ;
NSArray * publicCommentsArray = [ story objectForKey : @ "public_comments" ] ;
2013-03-05 12:26:37 -08:00
2013-03-05 17:00:03 -08:00
if ( [ [ story objectForKey : @ "comment_count_friends" ] intValue ] > 0 ) {
2015-09-16 20:24:11 -07:00
comments = [ comments stringByAppendingString : @ "<div class=\" NB - story - comments - group NB - story - comment - friend - comments \ ">" ] ;
2013-03-05 17:00:03 -08:00
NSString * commentHeader = [ NSString stringWithFormat : @
"<div class=\" NB - story - comments - friends - header - wrapper \ ">"
" <div class=\" NB - story - comments - friends - header \ ">%i comment%@</div>"
"</div>" ,
[ [ story objectForKey : @ "comment_count_friends" ] intValue ] ,
[ [ story objectForKey : @ "comment_count_friends" ] intValue ] = = 1 ? @ "" : @ "s" ] ;
comments = [ comments stringByAppendingString : commentHeader ] ;
// add friends comments
2015-09-16 20:24:11 -07:00
comments = [ comments stringByAppendingFormat : @ "<div class=\" NB - feed - story - comments \ ">" ] ;
2013-03-05 17:00:03 -08:00
for ( int i = 0 ; i < friendsCommentsArray . count ; i + + ) {
NSString * comment = [ self getComment : [ friendsCommentsArray objectAtIndex : i ] ] ;
comments = [ comments stringByAppendingString : comment ] ;
}
2015-09-08 14:17:01 -07:00
comments = [ comments stringByAppendingString : @ "</div>" ] ;
2015-09-16 20:24:11 -07:00
comments = [ comments stringByAppendingString : @ "</div>" ] ;
2015-09-07 19:56:44 -07:00
}
2015-09-07 21:39:51 -07:00
NSInteger sharedByFriendsCount = [ [ story objectForKey : @ "shared_by_friends" ] count ] ;
if ( sharedByFriendsCount > 0 ) {
2015-09-16 20:24:11 -07:00
comments = [ comments stringByAppendingString : @ "<div class=\" NB - story - comments - group NB - story - comment - friend - shares \ ">" ] ;
2015-09-07 19:56:44 -07:00
NSString * commentHeader = [ NSString stringWithFormat : @
2015-09-07 21:39:51 -07:00
"<div class=\" NB - story - comments - friend - shares - header - wrapper \ ">"
" <div class=\" NB - story - comments - friends - header \ ">%ld share%@</div>"
2015-09-07 19:56:44 -07:00
"</div>" ,
2015-09-07 21:39:51 -07:00
( long ) sharedByFriendsCount ,
sharedByFriendsCount = = 1 ? @ "" : @ "s" ] ;
2015-09-07 19:56:44 -07:00
comments = [ comments stringByAppendingString : commentHeader ] ;
2015-09-16 20:24:11 -07:00
// add friend shares
comments = [ comments stringByAppendingFormat : @ "<div class=\" NB - feed - story - comments \ ">" ] ;
2015-09-07 21:39:51 -07:00
for ( int i = 0 ; i < friendsShareArray . count ; i + + ) {
NSString * comment = [ self getComment : [ friendsShareArray objectAtIndex : i ] ] ;
2015-09-07 19:56:44 -07:00
comments = [ comments stringByAppendingString : comment ] ;
}
2015-09-08 14:17:01 -07:00
comments = [ comments stringByAppendingString : @ "</div>" ] ;
2015-09-16 20:24:11 -07:00
comments = [ comments stringByAppendingString : @ "</div>" ] ;
2015-09-07 19:56:44 -07:00
}
2012-08-07 11:27:00 -07:00
2013-07-19 17:53:52 -07:00
if ( [ [ [ NSUserDefaults standardUserDefaults ] objectForKey : @ "show_public_comments" ] boolValue ] &&
[ [ story objectForKey : @ "comment_count_public" ] intValue ] > 0 ) {
2015-09-16 20:24:11 -07:00
comments = [ comments stringByAppendingString : @ "<div class=\" NB - story - comments - group NB - story - comment - public - comments \ ">" ] ;
2012-08-07 11:27:00 -07:00
NSString * publicCommentHeader = [ NSString stringWithFormat : @
"<div class=\" NB - story - comments - public - header - wrapper \ ">"
2013-03-05 12:26:37 -08:00
" <div class=\" NB - story - comments - public - header \ ">%i public comment%@</div>"
2012-08-07 11:27:00 -07:00
"</div>" ,
[ [ story objectForKey : @ "comment_count_public" ] intValue ] ,
[ [ story objectForKey : @ "comment_count_public" ] intValue ] = = 1 ? @ "" : @ "s" ] ;
comments = [ comments stringByAppendingString : publicCommentHeader ] ;
2013-03-05 12:26:37 -08:00
comments = [ comments stringByAppendingFormat : @ "<div class=\" NB - feed - story - comments \ ">" ] ;
2013-03-05 17:00:03 -08:00
2013-03-05 12:26:37 -08:00
// add public comments
2012-08-07 11:27:00 -07:00
for ( int i = 0 ; i < publicCommentsArray . count ; i + + ) {
NSString * comment = [ self getComment : [ publicCommentsArray objectAtIndex : i ] ] ;
comments = [ comments stringByAppendingString : comment ] ;
}
2015-09-08 14:17:01 -07:00
comments = [ comments stringByAppendingString : @ "</div>" ] ;
2016-02-06 14:40:07 -08:00
comments = [ comments stringByAppendingString : @ "</div>" ] ;
2012-08-07 11:27:00 -07:00
}
}
return comments ;
}
- ( NSString * ) getShareBar {
2012-08-13 15:34:53 -07:00
NSString * comments = @ "<div id=\" NB - share - bar - wrapper \ ">" ;
2012-08-10 09:45:44 -07:00
NSString * commentLabel = @ "" ;
NSString * shareLabel = @ "" ;
2012-11-05 17:16:10 -08:00
if ( ! [ [ self . activeStory objectForKey : @ "comment_count" ] isKindOfClass : [ NSNull class ] ] &&
[ [ self . activeStory objectForKey : @ "comment_count" ] intValue ] ) {
2012-08-10 09:45:44 -07:00
commentLabel = [ commentLabel stringByAppendingString : [ NSString stringWithFormat : @
"<div class=\" NB - story - comments - label \ ">"
2012-12-11 17:53:17 -08:00
"%@" // comment count
// "%@" // reply count
2012-08-10 09:45:44 -07:00
"</div>"
"<div class=\" NB - story - share - profiles NB - story - share - profiles - comments \ ">"
2012-12-11 17:53:17 -08:00
"%@" // friend avatars
"%@" // public avatars
2012-08-10 09:45:44 -07:00
"</div>" ,
2012-11-05 17:16:10 -08:00
[ [ self . activeStory objectForKey : @ "comment_count" ] intValue ] = = 1
2014-09-17 16:41:48 -07:00
? [ NSString stringWithFormat : @ "<b>1 comment</b>" ] :
2012-11-05 17:16:10 -08:00
[ NSString stringWithFormat : @ "<b>%@ comments</b>" , [ self . activeStory objectForKey : @ "comment_count" ] ] ,
2012-08-10 09:45:44 -07:00
2012-08-13 15:34:53 -07:00
// replyStr ,
2012-08-10 09:45:44 -07:00
[ self getAvatars : @ "commented_by_friends" ] ,
[ self getAvatars : @ "commented_by_public" ] ] ] ;
}
2012-11-05 17:16:10 -08:00
if ( ! [ [ self . activeStory objectForKey : @ "share_count" ] isKindOfClass : [ NSNull class ] ] &&
[ [ self . activeStory objectForKey : @ "share_count" ] intValue ] ) {
2012-08-10 09:45:44 -07:00
shareLabel = [ shareLabel stringByAppendingString : [ NSString stringWithFormat : @
2012-08-13 15:34:53 -07:00
"<div class=\" NB - right \ ">"
"<div class=\" NB - story - share - profiles NB - story - share - profiles - shares \ ">"
2012-08-10 09:45:44 -07:00
"%@" // friend avatars
"%@" // public avatars
2012-08-13 15:34:53 -07:00
"</div>"
2012-12-11 17:53:17 -08:00
"<div class=\" NB - story - share - label \ ">"
"%@" // comment count
"</div>"
2012-08-13 15:34:53 -07:00
"</div>" ,
[ self getAvatars : @ "shared_by_public" ] ,
[ self getAvatars : @ "shared_by_friends" ] ,
2012-11-05 17:16:10 -08:00
[ [ self . activeStory objectForKey : @ "share_count" ] intValue ] = = 1
2012-08-10 09:45:44 -07:00
? [ NSString stringWithFormat : @ "<b>1 share</b>" ] :
2012-11-05 17:16:10 -08:00
[ NSString stringWithFormat : @ "<b>%@ shares</b>" , [ self . activeStory objectForKey : @ "share_count" ] ] ] ] ;
2012-08-10 09:45:44 -07:00
}
2012-08-07 11:27:00 -07:00
2012-11-05 17:16:10 -08:00
if ( [ self . activeStory objectForKey : @ "share_count" ] ! = [ NSNull null ] &&
[ [ self . activeStory objectForKey : @ "share_count" ] intValue ] > 0 ) {
2012-08-02 18:33:55 -07:00
2012-08-09 17:01:37 -07:00
comments = [ comments stringByAppendingString : [ NSString stringWithFormat : @
"<div class=\" NB - story - shares \ ">"
2012-12-11 17:53:17 -08:00
"<div class=\" NB - story - comments - shares - teaser - wrapper \ ">"
"<div class=\" NB - story - comments - shares - teaser \ ">"
"%@"
"%@"
"</div>"
"</div>"
"</div>" ,
2012-08-10 09:45:44 -07:00
commentLabel ,
shareLabel
2012-08-09 17:01:37 -07:00
] ] ;
2012-06-22 15:53:51 -07:00
}
2012-08-13 15:34:53 -07:00
comments = [ comments stringByAppendingString : [ NSString stringWithFormat : @ "</div>" ] ] ;
2012-06-22 15:53:51 -07:00
return comments ;
}
2012-06-22 18:01:08 -07:00
2012-06-25 20:28:07 -07:00
- ( NSString * ) getComment : ( NSDictionary * ) commentDict {
2016-02-01 10:44:59 -08:00
NSDictionary * user = [ appDelegate getUser : [ [ commentDict objectForKey : @ "user_id" ] intValue ] ] ;
2012-07-03 17:54:36 -07:00
NSString * userAvatarClass = @ "NB-user-avatar" ;
NSString * userReshareString = @ "" ;
2012-07-20 00:21:24 -07:00
NSString * userEditButton = @ "" ;
2012-07-23 10:57:11 -07:00
NSString * userLikeButton = @ "" ;
2012-07-20 00:21:24 -07:00
NSString * commentUserId = [ NSString stringWithFormat : @ "%@" , [ commentDict objectForKey : @ "user_id" ] ] ;
2016-02-01 10:44:59 -08:00
NSString * currentUserId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
2012-12-13 14:24:47 -08:00
NSArray * likingUsersArray = [ commentDict objectForKey : @ "liking_users" ] ;
NSString * likingUsers = @ "" ;
2012-07-26 13:54:45 -07:00
2012-12-13 14:24:47 -08:00
if ( [ likingUsersArray count ] ) {
likingUsers = @ "<div class=\" NB - story - comment - likes - icon \ "></div>" ;
for ( NSNumber * likingUser in likingUsersArray ) {
2016-02-01 10:44:59 -08:00
NSDictionary * sourceUser = [ appDelegate getUser : [ likingUser intValue ] ] ;
2012-12-13 14:24:47 -08:00
NSString * likingUserString = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment - likes - user \ ">"
" <div class=\" NB - user - avatar \ "><img src=\" % @ \ "></div>"
"</div>" ,
[ sourceUser objectForKey : @ "photo_url" ] ] ;
likingUsers = [ likingUsers stringByAppendingString : likingUserString ] ;
}
}
2012-07-20 00:21:24 -07:00
if ( [ commentUserId isEqualToString : currentUserId ] ) {
userEditButton = [ NSString stringWithFormat : @
2012-07-23 10:57:11 -07:00
"<div class=\" NB - story - comment - edit - button NB - story - comment - share - edit - button NB - button \ ">"
2012-08-08 12:02:54 -07:00
"<a href=\" http : // ios . newsblur . com / edit - share / % @ \ "><div class=\" NB - story - comment - edit - button - wrapper \ ">"
"Edit"
"</div></a>"
2012-07-20 18:04:54 -07:00
"</div>" ,
commentUserId ] ;
2012-07-23 10:57:11 -07:00
} else {
2012-07-26 13:54:45 -07:00
BOOL isInLikingUsers = NO ;
2012-12-13 14:24:47 -08:00
for ( int i = 0 ; i < likingUsersArray . count ; i + + ) {
if ( [ [ [ likingUsersArray objectAtIndex : i ] stringValue ] isEqualToString : currentUserId ] ) {
2012-07-26 13:54:45 -07:00
isInLikingUsers = YES ;
break ;
}
}
if ( isInLikingUsers ) {
userLikeButton = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment - like - button NB - button selected \ ">"
2012-08-08 12:02:54 -07:00
"<a href=\" http : // ios . newsblur . com / unlike - comment / % @ \ "><div class=\" NB - story - comment - like - button - wrapper \ ">"
2012-12-11 17:53:17 -08:00
"<span class=\" NB - favorite - icon \ "></span>"
2012-08-08 12:02:54 -07:00
"</div></a>"
2012-07-26 13:54:45 -07:00
"</div>" ,
commentUserId ] ;
} else {
userLikeButton = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment - like - button NB - button \ ">"
2012-08-08 12:02:54 -07:00
"<a href=\" http : // ios . newsblur . com / like - comment / % @ \ "><div class=\" NB - story - comment - like - button - wrapper \ ">"
2012-12-11 17:53:17 -08:00
"<span class=\" NB - favorite - icon \ "></span>"
2012-08-08 12:02:54 -07:00
"</div></a>"
2012-07-26 13:54:45 -07:00
"</div>" ,
commentUserId ] ;
}
2012-07-20 00:21:24 -07:00
}
2012-07-03 17:54:36 -07:00
if ( [ commentDict objectForKey : @ "source_user_id" ] ! = [ NSNull null ] ) {
userAvatarClass = @ "NB-user-avatar NB-story-comment-reshare" ;
2016-02-01 10:44:59 -08:00
NSDictionary * sourceUser = [ appDelegate getUser : [ [ commentDict objectForKey : @ "source_user_id" ] intValue ] ] ;
2012-07-03 17:54:36 -07:00
userReshareString = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment - reshares \ ">"
" <div class=\" NB - story - share - profile \ ">"
" <div class=\" NB - user - avatar \ "><img src=\" % @ \ "></div>"
" </div>"
"</div>" ,
2012-07-11 10:33:39 -07:00
[ sourceUser objectForKey : @ "photo_url" ] ] ;
2012-07-03 17:54:36 -07:00
}
2012-07-23 16:17:49 -07:00
NSString * commentContent = [ self textToHtml : [ commentDict objectForKey : @ "comments" ] ] ;
2012-07-29 13:24:03 -07:00
NSString * comment ;
2012-08-09 16:34:59 -07:00
NSString * locationHtml = @ "" ;
NSString * location = [ NSString stringWithFormat : @ "%@" , [ user objectForKey : @ "location" ] ] ;
2013-09-05 16:34:39 -07:00
if ( location . length && ! [ [ user objectForKey : @ "location" ] isKindOfClass : [ NSNull class ] ] ) {
2012-08-09 16:34:59 -07:00
locationHtml = [ NSString stringWithFormat : @ "<div class=\" NB - story - comment - location \ ">%@</div>" , location ] ;
}
2012-07-29 13:24:03 -07:00
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact ) {
2012-07-29 13:24:03 -07:00
comment = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment \ " id=\" NB - user - comment - % @ \ ">"
2012-12-11 11:50:06 -08:00
"<div class=\" % @ \ ">"
"<a class=\" NB - show - profile \ " href=\" http : // ios . newsblur . com / show - profile / % @ \ ">"
"<div class=\" NB - highlight \ "></div>"
"<img src=\" % @ \ " />"
"</a>"
"</div>"
2012-07-29 13:24:03 -07:00
"<div class=\" NB - story - comment - author - container \ ">"
" %@"
" <div class=\" NB - story - comment - username \ ">%@</div>"
" <div class=\" NB - story - comment - date \ ">%@ ago</div>"
2012-12-13 14:24:47 -08:00
" <div class=\" NB - story - comment - likes \ ">%@</div>"
2012-12-11 17:53:17 -08:00
"</div>"
"<div class=\" NB - story - comment - content \ ">%@</div>"
"%@" // location
"<div class=\" NB - button - wrapper \ ">"
2012-07-29 13:24:03 -07:00
" <div class=\" NB - story - comment - reply - button NB - button \ ">"
2012-08-08 12:02:54 -07:00
" <a href=\" http : // ios . newsblur . com / reply / % @ / % @ \ "><div class=\" NB - story - comment - reply - button - wrapper \ ">"
" Reply"
" </div></a>"
2012-07-29 13:24:03 -07:00
" </div>"
2012-12-11 17:53:17 -08:00
" %@" // User Like Button
" %@" // User Edit Button
2012-07-29 13:24:03 -07:00
"</div>"
"%@"
"</div>" ,
[ commentDict objectForKey : @ "user_id" ] ,
userAvatarClass ,
[ commentDict objectForKey : @ "user_id" ] ,
[ user objectForKey : @ "photo_url" ] ,
userReshareString ,
[ user objectForKey : @ "username" ] ,
[ commentDict objectForKey : @ "shared_date" ] ,
2012-12-13 14:24:47 -08:00
likingUsers ,
2012-12-11 17:53:17 -08:00
commentContent ,
locationHtml ,
2012-08-13 15:34:53 -07:00
[ commentDict objectForKey : @ "user_id" ] ,
[ user objectForKey : @ "username" ] ,
2012-12-11 17:53:17 -08:00
userEditButton ,
userLikeButton ,
[ self getReplies : [ commentDict objectForKey : @ "replies" ] forUserId : [ commentDict objectForKey : @ "user_id" ] ] ] ;
2012-07-29 13:24:03 -07:00
} else {
comment = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment \ " id=\" NB - user - comment - % @ \ ">"
2012-12-11 11:50:06 -08:00
"<div class=\" % @ \ ">"
"<a class=\" NB - show - profile \ " href=\" http : // ios . newsblur . com / show - profile / % @ \ ">"
"<div class=\" NB - highlight \ "></div>"
"<img src=\" % @ \ " />"
"</a>"
"</div>"
2012-07-29 13:24:03 -07:00
"<div class=\" NB - story - comment - author - container \ ">"
2012-12-11 17:53:17 -08:00
" %@"
2012-07-29 13:24:03 -07:00
" <div class=\" NB - story - comment - username \ ">%@</div>"
" <div class=\" NB - story - comment - date \ ">%@ ago</div>"
2012-12-13 16:41:52 -08:00
" <div class=\" NB - story - comment - likes \ ">%@</div>"
2012-07-29 13:24:03 -07:00
"</div>"
2012-08-13 16:20:23 -07:00
"<div class=\" NB - story - comment - content \ ">%@</div>"
2012-12-11 17:53:17 -08:00
"%@" // location
"<div class=\" NB - button - wrapper \ ">"
2012-07-29 13:24:03 -07:00
" <div class=\" NB - story - comment - reply - button NB - button \ ">"
2012-08-08 12:02:54 -07:00
" <a href=\" http : // ios . newsblur . com / reply / % @ / % @ \ "><div class=\" NB - story - comment - reply - button - wrapper \ ">"
" Reply"
" </div></a>"
2012-07-29 13:24:03 -07:00
" </div>"
2012-12-11 17:53:17 -08:00
" %@" // User Like Button
" %@" // User Edit Button
2012-07-29 13:24:03 -07:00
"</div>"
"%@"
"</div>" ,
[ commentDict objectForKey : @ "user_id" ] ,
userAvatarClass ,
[ commentDict objectForKey : @ "user_id" ] ,
[ user objectForKey : @ "photo_url" ] ,
userReshareString ,
[ user objectForKey : @ "username" ] ,
[ commentDict objectForKey : @ "shared_date" ] ,
2012-12-13 16:41:52 -08:00
likingUsers ,
2012-08-02 00:57:01 -07:00
commentContent ,
2012-12-11 17:53:17 -08:00
locationHtml ,
2012-08-13 16:20:23 -07:00
[ commentDict objectForKey : @ "user_id" ] ,
[ user objectForKey : @ "username" ] ,
2012-12-11 17:53:17 -08:00
userEditButton ,
userLikeButton ,
2012-07-29 13:24:03 -07:00
[ self getReplies : [ commentDict objectForKey : @ "replies" ] forUserId : [ commentDict objectForKey : @ "user_id" ] ] ] ;
2012-07-03 17:54:36 -07:00
2012-07-29 13:24:03 -07:00
}
2012-06-25 20:28:07 -07:00
return comment ;
}
2012-07-20 15:54:10 -07:00
- ( NSString * ) getReplies : ( NSArray * ) replies forUserId : ( NSString * ) commentUserId {
2012-06-22 18:01:08 -07:00
NSString * repliesString = @ "" ;
if ( replies . count > 0 ) {
repliesString = [ repliesString stringByAppendingString : @ "<div class=\" NB - story - comment - replies \ ">" ] ;
for ( int i = 0 ; i < replies . count ; i + + ) {
2012-07-20 15:54:10 -07:00
NSDictionary * replyDict = [ replies objectAtIndex : i ] ;
2016-02-01 10:44:59 -08:00
NSDictionary * user = [ appDelegate getUser : [ [ replyDict objectForKey : @ "user_id" ] intValue ] ] ;
2012-07-20 15:54:10 -07:00
NSString * userEditButton = @ "" ;
NSString * replyUserId = [ NSString stringWithFormat : @ "%@" , [ replyDict objectForKey : @ "user_id" ] ] ;
2012-07-30 14:58:57 -07:00
NSString * replyId = [ replyDict objectForKey : @ "reply_id" ] ;
2016-02-01 10:44:59 -08:00
NSString * currentUserId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
2012-07-20 15:54:10 -07:00
if ( [ replyUserId isEqualToString : currentUserId ] ) {
userEditButton = [ NSString stringWithFormat : @
2012-07-23 10:57:11 -07:00
"<div class=\" NB - story - comment - edit - button NB - story - comment - share - edit - button NB - button \ ">"
2012-08-08 12:02:54 -07:00
"<a href=\" http : // ios . newsblur . com / edit - reply / % @ / % @ / % @ \ ">"
2012-07-20 15:54:10 -07:00
"<div class=\" NB - story - comment - edit - button - wrapper \ ">"
2012-08-13 16:20:23 -07:00
"Edit"
2012-07-20 15:54:10 -07:00
"</div>"
2012-08-08 12:02:54 -07:00
"</a>"
2012-07-20 15:54:10 -07:00
"</div>" ,
commentUserId ,
replyUserId ,
2012-07-30 14:58:57 -07:00
replyId
2012-07-20 15:54:10 -07:00
] ;
}
2012-07-23 16:17:49 -07:00
NSString * replyContent = [ self textToHtml : [ replyDict objectForKey : @ "comments" ] ] ;
2012-08-09 16:45:52 -07:00
NSString * locationHtml = @ "" ;
NSString * location = [ NSString stringWithFormat : @ "%@" , [ user objectForKey : @ "location" ] ] ;
if ( location . length ) {
locationHtml = [ NSString stringWithFormat : @ "<div class=\" NB - story - comment - location \ ">%@</div>" , location ] ;
}
2012-07-21 18:25:56 -07:00
2012-08-13 15:34:53 -07:00
NSString * reply ;
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact ) {
2012-08-13 15:34:53 -07:00
reply = [ NSString stringWithFormat : @
2012-12-11 17:53:17 -08:00
"<div class=\" NB - story - comment - reply \ " id=\" NB - user - comment - % @ \ ">"
" <a class=\" NB - show - profile \ " href=\" http : // ios . newsblur . com / show - profile / % @ \ ">"
" <div class=\" NB - highlight \ "></div>"
" <img class=\" NB - story - comment - reply - photo \ " src=\" % @ \ " />"
" </a>"
" <div class=\" NB - story - comment - username NB - story - comment - reply - username \ ">%@</div>"
" <div class=\" NB - story - comment - date NB - story - comment - reply - date \ ">%@ ago</div>"
" <div class=\" NB - story - comment - reply - content \ ">%@</div>"
" %@" // location
" <div class=\" NB - button - wrapper \ ">"
" %@" // edit
" </div>"
"</div>" ,
[ replyDict objectForKey : @ "reply_id" ] ,
[ user objectForKey : @ "user_id" ] ,
[ user objectForKey : @ "photo_url" ] ,
[ user objectForKey : @ "username" ] ,
[ replyDict objectForKey : @ "publish_date" ] ,
replyContent ,
locationHtml ,
userEditButton ] ;
2012-08-13 15:34:53 -07:00
} else {
2012-08-13 16:20:23 -07:00
reply = [ NSString stringWithFormat : @
"<div class=\" NB - story - comment - reply \ " id=\" NB - user - comment - % @ \ ">"
" <a class=\" NB - show - profile \ " href=\" http : // ios . newsblur . com / show - profile / % @ \ ">"
2012-12-11 11:50:06 -08:00
" <div class=\" NB - highlight \ "></div>"
2012-08-13 16:20:23 -07:00
" <img class=\" NB - story - comment - reply - photo \ " src=\" % @ \ " />"
" </a>"
" <div class=\" NB - story - comment - username NB - story - comment - reply - username \ ">%@</div>"
" <div class=\" NB - story - comment - date NB - story - comment - reply - date \ ">%@ ago</div>"
" <div class=\" NB - story - comment - reply - content \ ">%@</div>"
2012-12-11 17:53:17 -08:00
" %@"
" <div class=\" NB - button - wrapper \ ">"
" %@" // edit
" </div>"
2012-08-13 16:20:23 -07:00
"</div>" ,
[ replyDict objectForKey : @ "reply_id" ] ,
[ user objectForKey : @ "user_id" ] ,
[ user objectForKey : @ "photo_url" ] ,
[ user objectForKey : @ "username" ] ,
[ replyDict objectForKey : @ "publish_date" ] ,
replyContent ,
2012-12-11 17:53:17 -08:00
locationHtml ,
2012-08-13 16:20:23 -07:00
userEditButton ] ;
2012-08-13 15:34:53 -07:00
}
2012-06-22 18:01:08 -07:00
repliesString = [ repliesString stringByAppendingString : reply ] ;
}
repliesString = [ repliesString stringByAppendingString : @ "</div>" ] ;
}
return repliesString ;
}
2016-08-10 13:26:52 -07:00
# pragma mark - Scrolling
2012-10-04 10:59:44 -07:00
- ( void ) observeValueForKeyPath : ( NSString * ) keyPath ofObject : ( id ) object change : ( NSDictionary * ) change context : ( void * ) context {
2016-02-01 10:44:59 -08:00
if ( [ keyPath isEqual : @ "contentOffset" ] ) {
2021-01-29 20:10:53 -08:00
BOOL isHorizontal = appDelegate . storyPagesViewController . isHorizontal ;
BOOL isNavBarHidden = appDelegate . storyPagesViewController . isNavigationBarHidden ;
2020-06-28 17:09:50 -07:00
2020-09-22 17:28:14 -07:00
if ( self . webView . scrollView . contentOffset . y < ( -1 * self . feedTitleGradient . frame . size . height + 1 + self . webView . scrollView . verticalScrollIndicatorInsets . top ) ) {
2012-10-04 10:59:44 -07:00
// Pulling
2016-02-01 10:44:59 -08:00
if ( ! pullingScrollview ) {
pullingScrollview = YES ;
2012-10-04 10:59:44 -07:00
for ( id subview in self . webView . scrollView . subviews ) {
UIImageView * imgView = [ subview isKindOfClass : [ UIImageView class ] ] ?
( UIImageView * ) subview : nil ;
// image views whose image is 1 px wide are shadow images , hide them
2013-03-06 14:29:40 -08:00
if ( imgView && imgView . image . size . width > 1 ) {
[ self . webView . scrollView insertSubview : self . feedTitleGradient
belowSubview : subview ] ;
[ self . webView . scrollView bringSubviewToFront : subview ] ;
2012-10-04 10:59:44 -07:00
}
}
}
} else {
// Normal reading
2016-02-01 10:44:59 -08:00
if ( pullingScrollview ) {
pullingScrollview = NO ;
2012-10-04 10:59:44 -07:00
[ self . feedTitleGradient . layer setShadowOpacity : 0 ] ;
2020-06-28 17:09:50 -07:00
if ( ! isNavBarHidden ) {
[ self . webView insertSubview : self . feedTitleGradient aboveSubview : self . webView . scrollView ] ;
self . feedTitleGradient . frame = CGRectMake ( 0 , -1 ,
self . feedTitleGradient . frame . size . width ,
self . feedTitleGradient . frame . size . height ) ;
}
2012-10-04 10:59:44 -07:00
for ( id subview in self . webView . scrollView . subviews ) {
UIImageView * imgView = [ subview isKindOfClass : [ UIImageView class ] ] ?
( UIImageView * ) subview : nil ;
// image views whose image is 1 px wide are shadow images , hide them
if ( imgView && imgView . image . size . width = = 1 ) {
imgView . hidden = NO ;
}
}
2011-10-28 10:51:03 -07:00
}
2011-10-27 19:05:38 -07:00
}
2013-03-06 14:29:40 -08:00
2021-01-29 20:10:53 -08:00
if ( appDelegate . storyPagesViewController . currentPage ! = self ) return ;
2015-10-06 18:52:58 -07:00
2013-03-07 10:55:23 -05:00
int webpageHeight = self . webView . scrollView . contentSize . height ;
2017-11-05 18:22:58 -08:00
int viewportHeight = self . view . frame . size . height ;
2013-03-07 10:55:23 -05:00
int topPosition = self . webView . scrollView . contentOffset . y ;
2019-05-29 15:11:52 -07:00
2021-02-25 20:33:22 -08:00
CGFloat bottomInset = appDelegate . detailViewController . view . safeAreaInsets . bottom ;
2017-11-05 18:44:33 -08:00
2022-02-01 20:40:07 -08:00
int safeBottomMargin = bottomInset ;
2013-03-07 10:55:23 -05:00
int bottomPosition = webpageHeight - topPosition - viewportHeight ;
2014-05-21 13:21:40 -07:00
BOOL singlePage = webpageHeight - 200 <= viewportHeight ;
BOOL atBottom = bottomPosition < 150 ;
2021-01-30 20:33:29 -08:00
BOOL pullingDown = topPosition < 0 ;
2021-02-25 19:49:39 -08:00
BOOL atTop = topPosition < 50 ;
2019-01-16 19:15:07 -08:00
BOOL nearTop = topPosition < 100 ;
2017-10-26 12:50:04 -07:00
if ( ! hasScrolled && topPosition ! = 0 ) {
hasScrolled = YES ;
}
2018-12-13 08:22:37 -08:00
2022-01-25 15:14:30 -08:00
if ( hasScrolled && ! atTop && [ appDelegate . storiesCollection isStoryUnread : activeStory ] ) {
2021-07-03 16:36:52 -07:00
[ appDelegate . storiesCollection markStoryRead : activeStory ] ;
[ appDelegate . storiesCollection syncStoryAsRead : activeStory ] ;
2023-05-25 21:47:34 -07:00
NSIndexPath * reloadIndexPath = appDelegate . feedDetailViewController . storyTitlesTable . indexPathForSelectedRow ;
if ( reloadIndexPath ! = nil ) {
2023-07-21 21:15:24 -06:00
[ appDelegate . feedDetailViewController reloadIndexPath : reloadIndexPath withRowAnimation : UITableViewRowAnimationNone ] ;
2023-05-25 21:47:34 -07:00
}
2021-07-03 16:36:52 -07:00
}
2021-06-12 21:51:08 -07:00
2021-01-30 20:33:29 -08:00
if ( ! isNavBarHidden && self . canHideNavigationBar && ! nearTop ) {
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController setNavigationBarHidden : YES ] ;
2018-12-13 08:22:37 -08:00
}
2021-01-30 20:33:29 -08:00
if ( isNavBarHidden && pullingDown ) {
[ appDelegate . storyPagesViewController setNavigationBarHidden : NO ] ;
}
2014-05-21 13:21:40 -07:00
if ( ! atTop && ! atBottom && ! singlePage ) {
2021-01-29 20:10:53 -08:00
BOOL traversalVisible = appDelegate . storyPagesViewController . traverseView . alpha > 0 ;
2019-05-16 13:58:03 -07:00
2013-03-06 14:29:40 -08:00
// Hide
[ UIView animateWithDuration : .3 delay : 0
options : UIViewAnimationOptionCurveEaseInOut
animations : ^ {
2021-01-29 20:10:53 -08:00
self . appDelegate . storyPagesViewController . traverseView . alpha = 0 ;
2019-05-16 13:58:03 -07:00
if ( traversalVisible ) {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideAutoscrollImmediately ] ;
2019-05-16 13:58:03 -07:00
}
2013-03-06 14:29:40 -08:00
} completion : ^ ( BOOL finished ) {
} ] ;
2019-02-27 13:33:38 -08:00
} else if ( singlePage || ! isHorizontal ) {
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . traverseView . alpha = 1 ;
2018-09-26 09:56:56 -04:00
// NSLog ( @ " ---> Bottom position: %d" , bottomPosition ) ;
2019-02-27 13:33:38 -08:00
if ( bottomPosition >= 0 || ! isHorizontal ) {
2022-02-01 20:40:07 -08:00
appDelegate . storyPagesViewController . traverseBottomConstraint . constant = 0 ;
2013-03-13 14:05:58 -07:00
} else {
2021-07-03 20:11:07 -07:00
if ( webpageHeight > 0 && [ [ UIDevice currentDevice ] userInterfaceIdiom ] = = UIUserInterfaceIdiomPhone ) {
2022-02-01 20:40:07 -08:00
appDelegate . storyPagesViewController . traverseBottomConstraint . constant = viewportHeight - ( webpageHeight - topPosition ) - safeBottomMargin ;
2020-05-26 14:13:46 -07:00
} else {
2022-02-01 20:40:07 -08:00
appDelegate . storyPagesViewController . traverseBottomConstraint . constant = 0 ;
2020-05-26 14:13:46 -07:00
}
2013-03-13 14:05:58 -07:00
}
2021-07-03 20:11:07 -07:00
} else if ( ( ! singlePage && ( atTop && ! atBottom ) ) || [ [ UIDevice currentDevice ] userInterfaceIdiom ] ! = UIUserInterfaceIdiomPhone ) {
2013-03-13 14:05:58 -07:00
// Pin to bottom of viewport , regardless of scrollview
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . traversePinned = YES ;
appDelegate . storyPagesViewController . traverseFloating = NO ;
[ appDelegate . storyPagesViewController . view layoutIfNeeded ] ;
2017-11-05 18:22:58 -08:00
2022-02-01 20:40:07 -08:00
appDelegate . storyPagesViewController . traverseBottomConstraint . constant = 0 ;
2021-08-24 21:01:28 -07:00
[ appDelegate . storyPagesViewController . view layoutIfNeeded ] ;
2013-03-06 14:29:40 -08:00
[ UIView animateWithDuration : .3 delay : 0
options : UIViewAnimationOptionCurveEaseInOut
animations : ^ {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController . view layoutIfNeeded ] ;
self . appDelegate . storyPagesViewController . traverseView . alpha = 1 ;
2013-07-17 18:14:04 -07:00
} completion : nil ] ;
2021-01-29 20:10:53 -08:00
} else if ( appDelegate . storyPagesViewController . traverseView . alpha = = 1 &&
appDelegate . storyPagesViewController . traversePinned ) {
2013-03-07 10:55:23 -05:00
// Scroll with bottom of scrollview , but smoothly
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . traverseFloating = YES ;
[ appDelegate . storyPagesViewController . view layoutIfNeeded ] ;
2017-11-05 18:22:58 -08:00
2022-02-01 20:40:07 -08:00
appDelegate . storyPagesViewController . traverseBottomConstraint . constant = 0 ;
2021-08-24 21:01:28 -07:00
[ appDelegate . storyPagesViewController . view layoutIfNeeded ] ;
2013-03-07 10:55:23 -05:00
[ UIView animateWithDuration : .3 delay : 0
options : UIViewAnimationOptionCurveEaseInOut
animations : ^ {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController . view layoutIfNeeded ] ;
2013-03-07 10:55:23 -05:00
} completion : ^ ( BOOL finished ) {
2021-01-29 20:10:53 -08:00
self . appDelegate . storyPagesViewController . traversePinned = NO ;
2013-03-07 10:55:23 -05:00
} ] ;
2013-03-06 14:29:40 -08:00
} else {
// Scroll with bottom of scrollview
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . traversePinned = NO ;
appDelegate . storyPagesViewController . traverseFloating = YES ;
appDelegate . storyPagesViewController . traverseView . alpha = 1 ;
2022-02-01 20:40:07 -08:00
appDelegate . storyPagesViewController . traverseBottomConstraint . constant = viewportHeight - ( webpageHeight - topPosition ) - safeBottomMargin ;
2013-03-06 14:29:40 -08:00
}
2015-09-16 21:34:41 -07:00
2021-02-26 15:00:46 -08:00
[ appDelegate . storyPagesViewController resizeScrollView ] ;
2015-09-17 13:15:10 -07:00
[ self storeScrollPosition : YES ] ;
}
}
2015-09-22 16:34:24 -07:00
- ( NSInteger ) scrollPosition {
NSInteger updatedPos = floor ( self . webView . scrollView . contentOffset . y / self . webView . scrollView . contentSize . height
* 1000 ) ;
return updatedPos ;
}
2015-09-17 13:15:10 -07:00
- ( void ) storeScrollPosition : ( BOOL ) queue {
2015-09-22 16:34:24 -07:00
__block NSInteger position = [ self scrollPosition ] ;
2015-09-22 13:10:35 -07:00
__block NSDictionary * story = self . activeStory ;
__weak __typeof ( & * self ) weakSelf = self ;
if ( position < 0 ) return ;
2017-10-26 12:50:04 -07:00
if ( ! hasScrolled ) return ;
2015-09-22 13:10:35 -07:00
NSString * storyIdentifier = [ NSString stringWithFormat : @ "markScrollPosition:%@" , [ story objectForKey : @ "story_hash" ] ] ;
if ( queue ) {
NSTimeInterval interval = 2 ;
[ JNWThrottledBlock runBlock : ^ {
__strong __typeof ( & * weakSelf ) strongSelf = weakSelf ;
if ( ! strongSelf ) return ;
2015-09-22 16:34:24 -07:00
NSInteger updatedPos = [ strongSelf scrollPosition ] ;
2020-08-27 15:08:46 -07:00
[ self . appDelegate markScrollPosition : updatedPos inStory : story ] ;
2015-09-22 13:10:35 -07:00
} withIdentifier : storyIdentifier throttle : interval ] ;
} else {
2015-10-02 16:04:49 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _LOW ,
2015-09-22 13:10:35 -07:00
( unsigned long ) NULL ) , ^ ( void ) {
2020-08-27 15:08:46 -07:00
[ self . appDelegate markScrollPosition : position inStory : story ] ;
2015-09-22 13:10:35 -07:00
} ) ;
2011-10-27 19:05:38 -07:00
}
2011-10-30 22:17:35 -07:00
}
2022-04-01 21:18:54 -07:00
- ( void ) realignScroll {
hasScrolled = NO ;
[ self scrollToLastPosition : YES ] ;
}
2015-09-28 20:01:17 -07:00
- ( void ) scrollToLastPosition : ( BOOL ) animated {
2016-02-01 10:44:59 -08:00
if ( hasScrolled ) return ;
hasScrolled = YES ;
2015-10-06 18:52:58 -07:00
2015-09-22 16:34:24 -07:00
__block NSString * storyHash = [ self . activeStory objectForKey : @ "story_hash" ] ;
__weak __typeof ( & * self ) weakSelf = self ;
2015-10-02 16:04:49 -07:00
dispatch_async ( dispatch_get _global _queue ( DISPATCH_QUEUE _PRIORITY _LOW ,
2015-09-22 16:34:24 -07:00
( unsigned long ) NULL ) , ^ ( void ) {
2020-08-27 15:08:46 -07:00
[ self . appDelegate . database inDatabase : ^ ( FMDatabase * db ) {
2015-09-22 16:34:24 -07:00
__strong __typeof ( & * weakSelf ) strongSelf = weakSelf ;
if ( ! strongSelf ) {
NSLog ( @ " !!! Lost strong reference to story detail vc" ) ;
return ;
}
FMResultSet * cursor = [ db executeQuery : @ "SELECT scroll, story_hash FROM story_scrolls s WHERE s.story_hash = ? LIMIT 1" , storyHash ] ;
while ( [ cursor next ] ) {
NSDictionary * story = [ cursor resultDictionary ] ;
id scroll = [ story objectForKey : @ "scroll" ] ;
2020-08-27 15:08:46 -07:00
if ( ( [ scroll isKindOfClass : [ NSNull class ] ] || [ scroll integerValue ] = = 0 ) && ! self -> scrollPct ) {
2017-10-26 12:50:04 -07:00
NSLog ( @ " ---> No scroll found for story: %@" , [ strongSelf . activeStory objectForKey : @ "story_title" ] ) ;
2015-09-22 16:34:24 -07:00
// No scroll found
continue ;
}
2017-09-26 10:48:02 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2020-08-27 15:08:46 -07:00
if ( ! self -> scrollPct ) self -> scrollPct = [ scroll floatValue ] / 1000. f ;
NSInteger position = floor ( self -> scrollPct * strongSelf . webView . scrollView . contentSize . height ) ;
2017-09-26 10:48:02 -07:00
NSInteger maxPosition = ( NSInteger ) ( floor ( strongSelf . webView . scrollView . contentSize . height - strongSelf . webView . frame . size . height ) ) ;
if ( position > maxPosition ) {
2023-08-29 16:33:12 -06:00
NSLog ( @ "Position too far, scaling back to max position: %@ > %@" , @ ( position ) , @ ( maxPosition ) ) ;
2017-09-26 10:48:02 -07:00
position = maxPosition ;
}
if ( position > 0 ) {
2020-08-27 15:08:46 -07:00
NSLog ( @ "Scrolling to %ld / %.1f%% (%.f+%.f) on %@-%@" , ( long ) position , self -> scrollPct * 100 , strongSelf . webView . scrollView . contentSize . height , strongSelf . webView . frame . size . height , [ story objectForKey : @ "story_hash" ] , [ strongSelf . activeStory objectForKey : @ "story_title" ] ) ;
2017-09-26 10:48:02 -07:00
[ strongSelf . webView . scrollView setContentOffset : CGPointMake ( 0 , position ) animated : animated ] ;
}
} ) ;
2015-09-22 16:34:24 -07:00
}
[ cursor close ] ;
} ] ;
} ) ;
}
2012-11-05 17:16:10 -08:00
- ( void ) setActiveStoryAtIndex : ( NSInteger ) activeStoryIndex {
if ( activeStoryIndex >= 0 ) {
2016-02-01 10:44:59 -08:00
self . activeStory = [ [ appDelegate . storiesCollection . activeFeedStories
2014-02-12 20:09:37 -08:00
objectAtIndex : activeStoryIndex ] mutableCopy ] ;
2012-11-05 17:16:10 -08:00
} else {
2016-02-01 10:44:59 -08:00
self . activeStory = [ appDelegate . activeStory mutableCopy ] ;
2012-11-05 17:16:10 -08:00
}
2011-12-01 09:01:18 -08:00
}
2020-02-23 15:21:32 -08:00
- ( void ) webView : ( WKWebView * ) webView decidePolicyForNavigationAction : ( WKNavigationAction * ) navigationAction decisionHandler : ( void ( ^ ) ( WKNavigationActionPolicy ) ) decisionHandler {
NSURLRequest * request = navigationAction . request ;
2016-02-01 10:44:59 -08:00
NSURL * url = [ request URL ] ;
2012-06-25 23:06:16 -07:00
NSArray * urlComponents = [ url pathComponents ] ;
2012-07-23 16:17:49 -07:00
NSString * action = @ "" ;
2012-12-27 18:37:05 -08:00
NSString * feedId = [ NSString stringWithFormat : @ "%@" , [ self . activeStory
objectForKey : @ "story_feed_id" ] ] ;
2012-07-23 16:17:49 -07:00
if ( [ urlComponents count ] > 1 ) {
action = [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 1 ] ] ;
}
2012-12-13 12:40:05 -08:00
2013-03-04 17:15:50 -08:00
// NSLog ( @ "Tapped url: %@" , url ) ;
2012-06-25 23:06:16 -07:00
// HACK : Using ios . newsblur . com to intercept the javascript share , reply , and edit events .
// the pathComponents do not work correctly unless it is a correctly formed url
// Is there a better way ? Someone show me the light
if ( [ [ url host ] isEqualToString : @ "ios.newsblur.com" ] ) {
2012-07-27 12:27:13 -07:00
// reset the active comment
2016-02-01 10:44:59 -08:00
appDelegate . activeComment = nil ;
appDelegate . activeShareType = action ;
2012-07-27 12:27:13 -07:00
2012-07-20 15:54:10 -07:00
if ( [ action isEqualToString : @ "reply" ] ||
[ action isEqualToString : @ "edit-reply" ] ||
2012-07-26 13:54:45 -07:00
[ action isEqualToString : @ "edit-share" ] ||
[ action isEqualToString : @ "like-comment" ] ||
[ action isEqualToString : @ "unlike-comment" ] ) {
2012-07-27 12:27:13 -07:00
2015-09-16 18:16:23 -07:00
// search for the comment from friends comments and shares
2012-11-05 17:16:10 -08:00
NSArray * friendComments = [ self . activeStory objectForKey : @ "friend_comments" ] ;
2012-07-20 00:21:24 -07:00
for ( int i = 0 ; i < friendComments . count ; i + + ) {
2012-06-25 23:06:16 -07:00
NSString * userId = [ NSString stringWithFormat : @ "%@" ,
2012-07-20 00:21:24 -07:00
[ [ friendComments objectAtIndex : i ] objectForKey : @ "user_id" ] ] ;
2012-06-25 23:06:16 -07:00
if ( [ userId isEqualToString : [ NSString stringWithFormat : @ "%@" ,
[ urlComponents objectAtIndex : 2 ] ] ] ) {
2016-02-01 10:44:59 -08:00
appDelegate . activeComment = [ friendComments objectAtIndex : i ] ;
2012-07-20 00:21:24 -07:00
}
}
2015-09-16 18:16:23 -07:00
NSArray * friendShares = [ self . activeStory objectForKey : @ "friend_shares" ] ;
for ( int i = 0 ; i < friendShares . count ; i + + ) {
NSString * userId = [ NSString stringWithFormat : @ "%@" ,
[ [ friendShares objectAtIndex : i ] objectForKey : @ "user_id" ] ] ;
if ( [ userId isEqualToString : [ NSString stringWithFormat : @ "%@" ,
[ urlComponents objectAtIndex : 2 ] ] ] ) {
2016-02-01 10:44:59 -08:00
appDelegate . activeComment = [ friendShares objectAtIndex : i ] ;
2015-09-16 18:16:23 -07:00
}
}
2016-02-01 10:44:59 -08:00
if ( appDelegate . activeComment = = nil ) {
2012-11-05 17:16:10 -08:00
NSArray * publicComments = [ self . activeStory objectForKey : @ "public_comments" ] ;
2012-07-20 00:21:24 -07:00
for ( int i = 0 ; i < publicComments . count ; i + + ) {
NSString * userId = [ NSString stringWithFormat : @ "%@" ,
[ [ publicComments objectAtIndex : i ] objectForKey : @ "user_id" ] ] ;
if ( [ userId isEqualToString : [ NSString stringWithFormat : @ "%@" ,
[ urlComponents objectAtIndex : 2 ] ] ] ) {
2016-02-01 10:44:59 -08:00
appDelegate . activeComment = [ publicComments objectAtIndex : i ] ;
2012-07-20 00:21:24 -07:00
}
2012-06-25 18:05:25 -07:00
}
}
2012-07-20 15:54:10 -07:00
2016-02-01 10:44:59 -08:00
if ( appDelegate . activeComment = = nil ) {
2012-07-27 12:27:13 -07:00
NSLog ( @ "PROBLEM! the active comment was not found in friend or public comments" ) ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2012-07-27 12:27:13 -07:00
}
2012-07-20 15:54:10 -07:00
if ( [ action isEqualToString : @ "reply" ] ) {
2016-02-01 10:44:59 -08:00
[ appDelegate showShareView : @ "reply"
2012-07-20 15:54:10 -07:00
setUserId : [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 2 ] ]
setUsername : [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 3 ] ]
2012-07-30 14:58:57 -07:00
setReplyId : nil ] ;
2012-07-20 15:54:10 -07:00
} else if ( [ action isEqualToString : @ "edit-reply" ] ) {
2016-02-01 10:44:59 -08:00
[ appDelegate showShareView : @ "edit-reply"
2012-07-20 15:54:10 -07:00
setUserId : [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 2 ] ]
setUsername : nil
2012-07-30 14:58:57 -07:00
setReplyId : [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 4 ] ] ] ;
2012-07-20 15:54:10 -07:00
} else if ( [ action isEqualToString : @ "edit-share" ] ) {
2016-02-01 10:44:59 -08:00
[ appDelegate showShareView : @ "edit-share"
2012-07-20 15:54:10 -07:00
setUserId : nil
setUsername : nil
2012-07-30 14:58:57 -07:00
setReplyId : nil ] ;
2012-07-26 13:54:45 -07:00
} else if ( [ action isEqualToString : @ "like-comment" ] ) {
[ self toggleLikeComment : YES ] ;
} else if ( [ action isEqualToString : @ "unlike-comment" ] ) {
[ self toggleLikeComment : NO ] ;
2012-07-20 15:54:10 -07:00
}
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2019-06-19 20:45:30 -07:00
} else if ( [ action isEqualToString : @ "togglechanges" ] ) {
if ( self . activeStory [ @ "story_changes" ] ! = nil ) {
[ self . activeStory removeObjectForKey : @ "story_changes" ] ;
[ self drawStory ] ;
} else {
[ self fetchStoryChanges ] ;
}
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2012-06-25 23:06:16 -07:00
} else if ( [ action isEqualToString : @ "share" ] ) {
2012-10-15 09:16:01 -07:00
[ self openShareDialog ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2013-09-26 19:26:10 -07:00
} else if ( [ action isEqualToString : @ "train" ] && [ urlComponents count ] > 5 ) {
2012-12-27 23:04:25 -08:00
[ self openTrainingDialog : [ [ urlComponents objectAtIndex : 2 ] intValue ]
yCoordinate : [ [ urlComponents objectAtIndex : 3 ] intValue ]
width : [ [ urlComponents objectAtIndex : 4 ] intValue ]
height : [ [ urlComponents objectAtIndex : 5 ] intValue ] ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2014-05-21 12:24:22 -07:00
} else if ( [ action isEqualToString : @ "save" ] ) {
2016-02-01 10:44:59 -08:00
BOOL isSaved = [ appDelegate . storiesCollection toggleStorySaved : self . activeStory ] ;
2014-12-16 15:36:58 -08:00
if ( isSaved ) {
[ self openUserTagsDialog : [ [ urlComponents objectAtIndex : 3 ] intValue ]
yCoordinate : [ [ urlComponents objectAtIndex : 4 ] intValue ]
width : [ [ urlComponents objectAtIndex : 5 ] intValue ]
height : [ [ urlComponents objectAtIndex : 6 ] intValue ] ] ;
}
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2014-11-10 16:00:59 -08:00
} else if ( [ action isEqualToString : @ "remove-user-tag" ] || [ action isEqualToString : @ "add-user-tag" ] ) {
[ self openUserTagsDialog : [ [ urlComponents objectAtIndex : 3 ] intValue ]
yCoordinate : [ [ urlComponents objectAtIndex : 4 ] intValue ]
width : [ [ urlComponents objectAtIndex : 5 ] intValue ]
height : [ [ urlComponents objectAtIndex : 6 ] intValue ] ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2012-12-07 17:18:31 -08:00
} else if ( [ action isEqualToString : @ "classify-author" ] ) {
NSString * author = [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 2 ] ] ;
2012-12-27 18:37:05 -08:00
[ self . appDelegate toggleAuthorClassifier : author feedId : feedId ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2012-12-07 17:18:31 -08:00
} else if ( [ action isEqualToString : @ "classify-tag" ] ) {
NSString * tag = [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 2 ] ] ;
2012-12-27 18:37:05 -08:00
[ self . appDelegate toggleTagClassifier : tag feedId : feedId ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2017-11-15 17:11:37 -08:00
} else if ( [ action isEqualToString : @ "premium" ] ) {
[ self . appDelegate showPremiumDialog ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2013-09-26 19:26:10 -07:00
} else if ( [ action isEqualToString : @ "show-profile" ] && [ urlComponents count ] > 6 ) {
2016-02-01 10:44:59 -08:00
appDelegate . activeUserProfileId = [ NSString stringWithFormat : @ "%@" , [ urlComponents objectAtIndex : 2 ] ] ;
2012-07-28 14:15:20 -07:00
2016-02-01 10:44:59 -08:00
for ( int i = 0 ; i < appDelegate . storiesCollection . activeFeedUserProfiles . count ; i + + ) {
NSString * userId = [ NSString stringWithFormat : @ "%@" , [ [ appDelegate . storiesCollection . activeFeedUserProfiles objectAtIndex : i ] objectForKey : @ "user_id" ] ] ;
if ( [ userId isEqualToString : appDelegate . activeUserProfileId ] ) {
appDelegate . activeUserProfileName = [ NSString stringWithFormat : @ "%@" , [ [ appDelegate . storiesCollection . activeFeedUserProfiles objectAtIndex : i ] objectForKey : @ "username" ] ] ;
2012-07-28 14:15:20 -07:00
break ;
}
}
2016-02-01 10:44:59 -08:00
2012-07-03 17:54:36 -07:00
[ self showUserProfile : [ urlComponents objectAtIndex : 2 ]
xCoordinate : [ [ urlComponents objectAtIndex : 3 ] intValue ]
yCoordinate : [ [ urlComponents objectAtIndex : 4 ] intValue ]
width : [ [ urlComponents objectAtIndex : 5 ] intValue ]
height : [ [ urlComponents objectAtIndex : 6 ] intValue ] ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2017-10-26 12:50:04 -07:00
} else if ( [ action isEqualToString : @ "notify-loaded" ] ) {
[ self webViewNotifyLoaded ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2012-06-22 13:15:31 -07:00
}
2012-12-13 16:41:52 -08:00
} else if ( [ url . host hasSuffix : @ "itunes.apple.com" ] ) {
2017-01-05 11:44:18 -08:00
[ [ UIApplication sharedApplication ] openURL : url options : @ { } completionHandler : nil ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2011-12-01 09:01:18 -08:00
}
2012-12-13 16:41:52 -08:00
2020-02-23 15:21:32 -08:00
if ( navigationAction . navigationType = = WKNavigationTypeLinkActivated ) {
2016-02-01 10:44:59 -08:00
// NSLog ( @ "Link clicked, views: %@ = %@" , appDelegate . navigationController . topViewController , appDelegate . masterContainerViewController . childViewControllers ) ;
2020-02-23 15:21:32 -08:00
if ( appDelegate . isPresentingActivities ) {
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
}
2016-02-01 10:44:59 -08:00
[ appDelegate showOriginalStory : url ] ;
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyCancel ) ;
return ;
2012-06-25 23:06:16 -07:00
}
2014-09-17 19:02:12 -07:00
2020-02-23 15:21:32 -08:00
decisionHandler ( WKNavigationActionPolicyAllow ) ;
2011-12-01 09:01:18 -08:00
}
2014-02-03 18:54:50 -08:00
- ( void ) showOriginalStory : ( UIGestureRecognizer * ) gesture {
2016-02-01 10:44:59 -08:00
NSURL * url = [ NSURL URLWithString : [ appDelegate . activeStory
2014-02-03 18:54:50 -08:00
objectForKey : @ "story_permalink" ] ] ;
2016-02-01 10:44:59 -08:00
[ appDelegate hidePopover ] ;
2014-02-03 18:54:50 -08:00
2014-02-04 12:40:46 -08:00
if ( ! gesture || [ gesture isKindOfClass : [ UITapGestureRecognizer class ] ] ) {
2016-02-01 10:44:59 -08:00
[ appDelegate showOriginalStory : url ] ;
2014-02-03 18:54:50 -08:00
return ;
}
if ( [ gesture isKindOfClass : [ UIPinchGestureRecognizer class ] ] &&
gesture . state = = UIGestureRecognizerStateChanged &&
[ gesture numberOfTouches ] >= 2 ) {
CGPoint touch1 = [ gesture locationOfTouch : 0 inView : self . view ] ;
CGPoint touch2 = [ gesture locationOfTouch : 1 inView : self . view ] ;
CGPoint slope = CGPointMake ( touch2 . x - touch1 . x , touch2 . y - touch1 . y ) ;
CGFloat distance = sqrtf ( slope . x * slope . x + slope . y * slope . y ) ;
CGFloat scale = [ ( UIPinchGestureRecognizer * ) gesture scale ] ;
2014-02-04 12:40:46 -08:00
// NSLog ( @ "Gesture: %f - %f" , [ ( UIPinchGestureRecognizer * ) gesture scale ] , distance ) ;
2014-02-03 18:54:50 -08:00
if ( ( distance < 150 && scale <= 1.5 ) ||
( distance < 500 && scale <= 1.2 ) ) {
return ;
}
2016-02-01 10:44:59 -08:00
[ appDelegate showOriginalStory : url ] ;
2014-02-03 18:54:50 -08:00
gesture . enabled = NO ;
gesture . enabled = YES ;
}
}
2012-07-03 17:54:36 -07:00
- ( void ) showUserProfile : ( NSString * ) userId xCoordinate : ( int ) x yCoordinate : ( int ) y width : ( int ) width height : ( int ) height {
2012-07-28 14:15:20 -07:00
CGRect frame = CGRectZero ;
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact ) {
2012-07-25 17:34:45 -07:00
// only adjust for the bar if user is scrolling
2016-02-01 10:44:59 -08:00
if ( appDelegate . storiesCollection . isRiverView ||
appDelegate . storiesCollection . isSocialView ||
appDelegate . storiesCollection . isSavedView ||
2022-03-09 19:16:43 -07:00
appDelegate . storiesCollection . isWidgetView ||
2016-02-01 10:44:59 -08:00
appDelegate . storiesCollection . isReadView ) {
2012-10-04 10:59:44 -07:00
if ( self . webView . scrollView . contentOffset . y = = -20 ) {
y = y + 20 ;
2012-07-25 17:34:45 -07:00
}
} else {
if ( self . webView . scrollView . contentOffset . y = = -9 ) {
y = y + 9 ;
}
}
2012-07-28 12:56:51 -07:00
frame = CGRectMake ( x , y , width , height ) ;
}
2016-02-01 10:44:59 -08:00
[ appDelegate showUserProfileModal : [ NSValue valueWithCGRect : frame ] ] ;
2012-07-03 17:54:36 -07:00
}
2020-02-23 15:21:32 -08:00
- ( void ) webView : ( WKWebView * ) webView didStartProvisionalNavigation : ( WKNavigation * ) navigation {
2016-08-23 20:52:34 -04:00
if ( ! self . hasStory ) // other Web page loads aren ' t visible
return ;
// DOM should already be set up here
2014-05-15 18:06:56 -07:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2013-11-23 13:03:14 -08:00
[ self changeFontSize : [ userPreferences stringForKey : @ "story_font_size" ] ] ;
2014-05-15 18:06:56 -07:00
[ self changeLineSpacing : [ userPreferences stringForKey : @ "story_line_spacing" ] ] ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : @ "document.body.style.webkitTouchCallout='none';" completionHandler : nil ] ;
2011-12-01 09:01:18 -08:00
}
2020-02-23 15:21:32 -08:00
- ( void ) webView : ( WKWebView * ) webView didFinishNavigation : ( WKNavigation * ) navigation {
2019-01-30 14:39:50 -08:00
[ self loadStory ] ;
}
2016-08-23 20:52:34 -04:00
2019-01-30 14:39:50 -08:00
- ( void ) loadStory {
2016-08-23 20:52:34 -04:00
if ( ! self . fullStoryHTML )
return ; // if we ' re loading anything other than a full story , the view will be hidden
2016-02-05 12:19:48 -08:00
2023-10-18 16:14:46 -06:00
NSLog ( @ "📚 loaded: %@" , self . activeStory [ @ "story_title" ] ) ; // log
2019-01-30 14:39:50 -08:00
[ self . activityIndicator stopAnimating ] ;
2023-03-30 10:36:31 -07:00
self . webView . scrollView . scrollEnabled = self . appDelegate . detailViewController . isPhone || ! self . appDelegate . detailViewController . storyTitlesInGrid ;
2023-03-03 21:38:55 -07:00
2016-08-23 20:52:34 -04:00
[ self loadHTMLString : self . fullStoryHTML ] ;
self . fullStoryHTML = nil ;
self . hasStory = YES ;
2016-02-05 12:19:48 -08:00
2012-07-31 23:49:51 -07:00
[ MBProgressHUD hideHUDForView : self . view animated : YES ] ;
2019-01-30 14:39:50 -08:00
2016-02-01 10:44:59 -08:00
if ( [ appDelegate . storiesCollection . activeFeedStories count ] &&
2016-08-23 20:52:34 -04:00
self . activeStoryId ) {
2016-02-01 10:44:59 -08:00
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , .15 * NSEC_PER _SEC ) ,
dispatch_get _main _queue ( ) , ^ {
2019-01-30 14:39:50 -08:00
[ self checkTryFeedStory ] ;
} ) ;
2016-02-01 10:44:59 -08:00
}
2019-01-30 14:39:50 -08:00
2020-04-21 16:05:31 -07:00
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , ( int64_t ) ( 0.1 * NSEC_PER _SEC ) ) , dispatch_get _main _queue ( ) , ^ {
2023-10-18 16:14:46 -06:00
NSLog ( @ "📚 showing webview for: %@; %@ current page" , self . activeStory [ @ "story_title" ] , self = = self . appDelegate . storyPagesViewController . currentPage ? @ "is" : @ "isn't" ) ; // log
2020-04-21 16:05:31 -07:00
self . webView . hidden = NO ;
[ self . webView setNeedsDisplay ] ;
2022-10-27 20:53:47 -06:00
2023-03-30 10:36:31 -07:00
if ( self = = self . appDelegate . storyPagesViewController . currentPage && ! self . appDelegate . detailViewController . isPhone && self . appDelegate . detailViewController . storyTitlesInGrid ) {
2022-10-27 20:53:47 -06:00
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , ( int64_t ) ( 0.4 * NSEC_PER _SEC ) ) , dispatch_get _main _queue ( ) , ^ {
2023-03-03 21:38:55 -07:00
// [ self . appDelegate . feedDetailViewController changedStoryHeight : self . webView . scrollView . contentSize . height ] ;
[ self . appDelegate . feedDetailViewController reload ] ;
2022-10-27 20:53:47 -06:00
} ) ;
}
2020-04-21 16:05:31 -07:00
} ) ;
2012-11-13 12:28:16 -08:00
}
2017-10-26 12:50:04 -07:00
- ( void ) webViewNotifyLoaded {
[ self scrollToLastPosition : YES ] ;
}
2012-11-13 12:28:16 -08:00
- ( void ) checkTryFeedStory {
2012-07-31 23:49:51 -07:00
// see if it ' s a tryfeed for animation
2012-11-09 14:13:44 -08:00
if ( ! self . webView . hidden &&
2016-02-01 10:44:59 -08:00
appDelegate . tryFeedCategory &&
( [ [ self . activeStory objectForKey : @ "id" ] isEqualToString : appDelegate . tryFeedStoryId ] ||
[ [ self . activeStory objectForKey : @ "story_hash" ] isEqualToString : appDelegate . tryFeedStoryId ] ) ) {
2021-01-29 20:10:53 -08:00
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . view animated : YES ] ;
2012-11-13 12:28:16 -08:00
2016-02-01 10:44:59 -08:00
if ( [ appDelegate . tryFeedCategory isEqualToString : @ "comment_like" ] ||
[ appDelegate . tryFeedCategory isEqualToString : @ "comment_reply" ] ) {
NSString * currentUserId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
2012-08-01 12:41:02 -07:00
NSString * jsFlashString = [ [ NSString alloc ] initWithFormat : @ "slideToComment('%@', true, true);" , currentUserId ] ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsFlashString completionHandler : nil ] ;
2016-02-01 10:44:59 -08:00
} else if ( [ appDelegate . tryFeedCategory isEqualToString : @ "story_reshare" ] ||
[ appDelegate . tryFeedCategory isEqualToString : @ "reply_reply" ] ) {
2012-11-05 17:16:10 -08:00
NSString * blurblogUserId = [ NSString stringWithFormat : @ "%@" , [ self . activeStory objectForKey : @ "social_user_id" ] ] ;
2012-11-28 16:24:15 -08:00
NSString * jsFlashString = [ [ NSString alloc ] initWithFormat : @ "slideToComment('%@', true, true);" , blurblogUserId ] ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsFlashString completionHandler : nil ] ;
2012-07-31 23:49:51 -07:00
}
2016-02-01 10:44:59 -08:00
appDelegate . tryFeedCategory = nil ;
2012-07-31 23:49:51 -07:00
}
2011-12-01 09:01:18 -08:00
}
2012-11-05 17:16:10 -08:00
- ( void ) setFontStyle : ( NSString * ) fontStyle {
2016-02-01 10:44:59 -08:00
NSString * jsString ;
2012-11-05 17:16:10 -08:00
NSUserDefaults * userPreferences = [ NSUserDefaults standardUserDefaults ] ;
2015-11-03 12:10:28 -08:00
[ userPreferences setObject : fontStyle forKey : @ "fontStyle" ] ;
2012-11-05 17:16:10 -08:00
[ userPreferences synchronize ] ;
jsString = [ NSString stringWithFormat : @
"document.getElementById('NB-font-style').setAttribute('class', '%@')" ,
2015-11-03 12:10:28 -08:00
fontStyle ] ;
2012-11-05 17:16:10 -08:00
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : nil ] ;
2016-02-01 10:44:59 -08:00
if ( ! [ fontStyle hasPrefix : @ "NB-" ] ) {
jsString = [ NSString stringWithFormat : @
"document.getElementById('NB-font-style').setAttribute('style', 'font-family: %@;')" ,
fontStyle ] ;
} else {
jsString = @ "document.getElementById('NB-font-style').setAttribute('style', '')" ;
}
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : nil ] ;
2012-07-25 10:50:52 -07:00
}
2012-11-05 17:16:10 -08:00
- ( void ) changeFontSize : ( NSString * ) fontSize {
2013-11-23 13:03:14 -08:00
NSString * jsString = [ [ NSString alloc ] initWithFormat : @ "document.getElementById('NB-font-size').setAttribute('class', 'NB-%@')" ,
2012-11-05 17:16:10 -08:00
fontSize ] ;
2012-07-28 11:49:31 -07:00
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : nil ] ;
2011-12-01 09:01:18 -08:00
}
2014-05-15 18:06:56 -07:00
- ( void ) changeLineSpacing : ( NSString * ) lineSpacing {
NSString * jsString = [ [ NSString alloc ] initWithFormat : @ "document.getElementById('NB-line-spacing').setAttribute('class', 'NB-line-spacing-%@')" ,
lineSpacing ] ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : nil ] ;
2014-05-15 18:06:56 -07:00
}
2018-10-22 15:14:12 -07:00
- ( void ) updateStoryTheme {
2021-08-25 20:45:46 -07:00
self . view . backgroundColor = UIColorFromRGB ( NEWSBLUR_WHITE _COLOR ) ;
2020-10-30 20:58:27 -07:00
2018-10-22 15:14:12 -07:00
NSString * jsString = [ NSString stringWithFormat : @ "document.getElementById('NB-theme-style').href='storyDetailView%@.css';" ,
[ ThemeManager themeManager ] . themeCSSSuffix ] ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : nil ] ;
2020-02-20 20:32:49 -08:00
2021-08-25 20:45:46 -07:00
self . webView . backgroundColor = UIColorFromRGB ( NEWSBLUR_WHITE _COLOR ) ;
2020-07-21 20:30:02 -07:00
if ( [ ThemeManager themeManager ] . isDarkTheme ) {
self . webView . scrollView . indicatorStyle = UIScrollViewIndicatorStyleWhite ;
} else {
self . webView . scrollView . indicatorStyle = UIScrollViewIndicatorStyleBlack ;
}
2018-10-22 15:14:12 -07:00
}
2018-12-13 08:22:37 -08:00
- ( BOOL ) canHideNavigationBar {
2021-01-29 20:10:53 -08:00
if ( ! appDelegate . storyPagesViewController . allowFullscreen ) {
2021-06-07 15:43:02 -04:00
// NSLog ( @ "canHideNavigationBar: no, toggle is off" ) ; // log
2019-01-16 19:15:07 -08:00
return NO ;
2018-12-24 14:39:28 -08:00
}
2020-06-20 21:31:21 -07:00
return YES ;
2018-12-13 08:22:37 -08:00
}
2019-04-16 20:24:42 -07:00
- ( BOOL ) isSinglePage {
NSInteger webpageHeight = self . webView . scrollView . contentSize . height ;
NSInteger viewportHeight = self . view . frame . size . height ;
return webpageHeight - 200 <= viewportHeight ;
}
2012-11-05 17:16:10 -08:00
# pragma mark -
# pragma mark Actions
2011-12-01 09:01:18 -08:00
2012-07-26 13:54:45 -07:00
- ( void ) toggleLikeComment : ( BOOL ) likeComment {
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController showShareHUD : @ "Favoriting" ] ;
2012-07-26 13:54:45 -07:00
NSString * urlString ;
if ( likeComment ) {
2013-06-18 21:23:20 -04:00
urlString = [ NSString stringWithFormat : @ "%@/social/like_comment" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2012-07-26 13:54:45 -07:00
} else {
2013-06-18 21:23:20 -04:00
urlString = [ NSString stringWithFormat : @ "%@/social/remove_like_comment" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2012-07-26 13:54:45 -07:00
}
2017-03-19 18:15:36 -07:00
NSMutableDictionary * params = [ NSMutableDictionary dictionary ] ;
[ params setObject : [ self . activeStory objectForKey : @ "id" ] forKey : @ "story_id" ] ;
[ params setObject : [ self . activeStory objectForKey : @ "story_feed_id" ] forKey : @ "story_feed_id" ] ;
2017-03-19 12:09:49 -07:00
[ params setObject : [ appDelegate . activeComment objectForKey : @ "user_id" ] forKey : @ "comment_user_id" ] ;
2012-07-26 13:54:45 -07:00
2019-08-22 12:03:39 -07:00
[ appDelegate POST : urlString parameters : params success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-03-19 18:15:36 -07:00
[ self finishLikeComment : responseObject ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
2017-06-01 22:32:35 -07:00
NSHTTPURLResponse * httpResponse = ( NSHTTPURLResponse * ) task . response ;
[ self requestFailed : error statusCode : httpResponse . statusCode ] ;
2017-03-19 18:15:36 -07:00
} ] ;
2012-07-26 13:54:45 -07:00
}
2017-03-19 18:15:36 -07:00
- ( void ) finishLikeComment : ( NSDictionary * ) results {
2012-07-26 13:54:45 -07:00
// add the comment into the activeStory dictionary
2016-02-01 10:44:59 -08:00
NSDictionary * newStory = [ DataUtilities updateComment : results for : appDelegate ] ;
2012-07-26 13:54:45 -07:00
// update the current story and the activeFeedStories
2016-02-01 10:44:59 -08:00
appDelegate . activeStory = newStory ;
2012-11-05 17:16:10 -08:00
[ self setActiveStoryAtIndex : -1 ] ;
2012-07-26 13:54:45 -07:00
NSMutableArray * newActiveFeedStories = [ [ NSMutableArray alloc ] init ] ;
2016-02-01 10:44:59 -08:00
for ( int i = 0 ; i < appDelegate . storiesCollection . activeFeedStories . count ; i + + ) {
NSDictionary * feedStory = [ appDelegate . storiesCollection . activeFeedStories objectAtIndex : i ] ;
2014-02-12 20:41:29 -08:00
NSString * storyId = [ NSString stringWithFormat : @ "%@" , [ feedStory objectForKey : @ "story_hash" ] ] ;
NSString * currentStoryId = [ NSString stringWithFormat : @ "%@" , [ self . activeStory objectForKey : @ "story_hash" ] ] ;
2012-07-26 13:54:45 -07:00
if ( [ storyId isEqualToString : currentStoryId ] ) {
[ newActiveFeedStories addObject : newStory ] ;
} else {
2016-02-01 10:44:59 -08:00
[ newActiveFeedStories addObject : [ appDelegate . storiesCollection . activeFeedStories objectAtIndex : i ] ] ;
2012-07-26 13:54:45 -07:00
}
}
2016-02-01 10:44:59 -08:00
appDelegate . storiesCollection . activeFeedStories = [ NSArray arrayWithArray : newActiveFeedStories ] ;
2012-07-26 13:54:45 -07:00
2021-01-29 20:10:53 -08:00
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . view animated : NO ] ;
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . currentPage . view animated : NO ] ;
2012-07-30 14:58:57 -07:00
[ self refreshComments : @ "like" ] ;
2012-07-26 13:54:45 -07:00
}
2017-06-01 22:32:35 -07:00
- ( void ) requestFailed : ( NSError * ) error statusCode : ( NSInteger ) statusCode {
2017-03-19 18:15:36 -07:00
NSLog ( @ "Error in story detail: %@" , error ) ;
2013-09-05 16:34:39 -07:00
2021-01-29 20:10:53 -08:00
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . view animated : NO ] ;
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . currentPage . view animated : NO ] ;
2017-04-06 11:45:43 -07:00
2017-06-01 22:32:35 -07:00
[ self informError : error statusCode : statusCode ] ;
2012-06-29 12:54:52 -07:00
}
2012-10-15 09:16:01 -07:00
- ( void ) openShareDialog {
// test to see if the user has commented
// search for the comment from friends comments
2012-11-05 17:16:10 -08:00
NSArray * friendComments = [ self . activeStory objectForKey : @ "friend_comments" ] ;
2015-09-16 18:16:23 -07:00
2016-02-01 10:44:59 -08:00
NSString * currentUserId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
2012-10-15 09:16:01 -07:00
for ( int i = 0 ; i < friendComments . count ; i + + ) {
NSString * userId = [ NSString stringWithFormat : @ "%@" ,
[ [ friendComments objectAtIndex : i ] objectForKey : @ "user_id" ] ] ;
if ( [ userId isEqualToString : currentUserId ] ) {
2016-02-01 10:44:59 -08:00
appDelegate . activeComment = [ friendComments objectAtIndex : i ] ;
2013-09-23 15:07:25 -07:00
break ;
} else {
2016-02-01 10:44:59 -08:00
appDelegate . activeComment = nil ;
2012-10-15 09:16:01 -07:00
}
}
2016-02-01 10:44:59 -08:00
if ( appDelegate . activeComment = = nil ) {
[ appDelegate showShareView : @ "share"
2012-10-15 09:16:01 -07:00
setUserId : nil
setUsername : nil
setReplyId : nil ] ;
} else {
2016-02-01 10:44:59 -08:00
[ appDelegate showShareView : @ "edit-share"
2012-10-15 09:16:01 -07:00
setUserId : nil
setUsername : nil
setReplyId : nil ] ;
}
}
2012-12-27 23:04:25 -08:00
- ( void ) openTrainingDialog : ( int ) x yCoordinate : ( int ) y width : ( int ) width height : ( int ) height {
CGRect frame = CGRectZero ;
2015-11-28 22:07:38 -08:00
if ( ! self . isPhoneOrCompact ) {
2012-12-27 23:04:25 -08:00
// only adjust for the bar if user is scrolling
2016-02-01 10:44:59 -08:00
if ( appDelegate . storiesCollection . isRiverView ||
appDelegate . storiesCollection . isSocialView ||
appDelegate . storiesCollection . isSavedView ||
2022-03-09 19:16:43 -07:00
appDelegate . storiesCollection . isWidgetView ||
2016-02-01 10:44:59 -08:00
appDelegate . storiesCollection . isReadView ) {
2012-12-27 23:04:25 -08:00
if ( self . webView . scrollView . contentOffset . y = = -20 ) {
y = y + 20 ;
}
} else {
if ( self . webView . scrollView . contentOffset . y = = -9 ) {
y = y + 9 ;
}
}
frame = CGRectMake ( x , y , width , height ) ;
}
2014-11-10 16:00:59 -08:00
// NSLog ( @ "Open trainer: %@ (%d/%d/%d/%d)" , NSStringFromCGRect ( frame ) , x , y , width , height ) ;
2016-02-01 10:44:59 -08:00
[ appDelegate openTrainStory : [ NSValue valueWithCGRect : frame ] ] ;
2012-12-27 23:04:25 -08:00
}
2014-11-10 16:00:59 -08:00
- ( void ) openUserTagsDialog : ( int ) x yCoordinate : ( int ) y width : ( int ) width height : ( int ) height {
CGRect frame = CGRectZero ;
// only adjust for the bar if user is scrolling
2016-02-01 10:44:59 -08:00
if ( appDelegate . storiesCollection . isRiverView ||
appDelegate . storiesCollection . isSocialView ||
appDelegate . storiesCollection . isSavedView ||
appDelegate . storiesCollection . isReadView ) {
2014-11-10 16:00:59 -08:00
if ( self . webView . scrollView . contentOffset . y = = -20 ) {
y = y + 20 ;
}
} else {
if ( self . webView . scrollView . contentOffset . y = = -9 ) {
y = y + 9 ;
}
}
frame = CGRectMake ( x , y , width , height ) ;
2016-02-01 10:44:59 -08:00
[ appDelegate openUserTagsStory : [ NSValue valueWithCGRect : frame ] ] ;
2014-11-10 16:00:59 -08:00
}
2021-12-07 19:40:59 -07:00
- ( BOOL ) isTag : ( NSString * ) tagName equalTo : ( NSString * ) tagValue {
return [ tagName isKindOfClass : [ NSString class ] ] && [ tagName isEqualToString : tagValue ] ;
}
2014-09-18 18:25:38 -07:00
- ( void ) tapImage : ( UIGestureRecognizer * ) gestureRecognizer {
2016-02-01 10:44:59 -08:00
CGPoint pt = [ self pointForGesture : gestureRecognizer ] ;
if ( pt . x = = CGPointZero . x && pt . y = = CGPointZero . y ) return ;
// NSLog ( @ "Tapped point: %@" , NSStringFromCGPoint ( pt ) ) ;
2020-02-23 15:21:32 -08:00
[ webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'tagName');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * tagName , NSError * error ) {
2021-12-07 19:40:59 -07:00
if ( [ self isTag : tagName equalTo : @ "IMG" ] ) {
2020-02-23 15:21:32 -08:00
[ self showImageMenu : pt ] ;
[ gestureRecognizer setEnabled : NO ] ;
[ gestureRecognizer setEnabled : YES ] ;
}
} ] ;
2014-09-18 16:55:37 -07:00
}
- ( void ) showImageMenu : ( CGPoint ) pt {
2020-08-27 15:08:46 -07:00
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'title');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * title , NSError * error ) {
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'alt');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * alt , NSError * error ) {
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'src');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * src , NSError * error ) {
2020-02-23 15:21:32 -08:00
NSString * alertTitle = title . length ? title : alt ;
2020-08-27 15:08:46 -07:00
self -> activeLongPressUrl = [ NSURL URLWithString : src ] ;
2020-02-23 15:21:32 -08:00
UIAlertController * alert = [ UIAlertController alertControllerWithTitle : alertTitle . length ? alertTitle : nil
message : nil
preferredStyle : UIAlertControllerStyleActionSheet ] ;
[ alert addAction : [ UIAlertAction actionWithTitle : @ "View and zoom" style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * _Nonnull action ) {
2020-08-27 15:08:46 -07:00
[ self . appDelegate showOriginalStory : self -> activeLongPressUrl ] ;
2020-02-23 15:21:32 -08:00
} ] ] ;
[ alert addAction : [ UIAlertAction actionWithTitle : @ "Copy image" style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * _Nonnull action ) {
2020-08-27 15:08:46 -07:00
[ self fetchImage : self -> activeLongPressUrl copy : YES save : NO ] ;
2020-02-23 15:21:32 -08:00
} ] ] ;
[ alert addAction : [ UIAlertAction actionWithTitle : @ "Save to camera roll" style : UIAlertActionStyleDefault handler : ^ ( UIAlertAction * _Nonnull action ) {
2020-08-27 15:08:46 -07:00
[ self fetchImage : self -> activeLongPressUrl copy : NO save : YES ] ;
2020-02-23 15:21:32 -08:00
} ] ] ;
[ alert addAction : [ UIAlertAction actionWithTitle : @ "Cancel" style : UIAlertActionStyleCancel handler : ^ ( UIAlertAction * _Nonnull action ) {
} ] ] ;
[ alert setModalPresentationStyle : UIModalPresentationPopover ] ;
UIPopoverPresentationController * popover = [ alert popoverPresentationController ] ;
popover . sourceRect = CGRectMake ( pt . x , pt . y , 1 , 1 ) ;
2021-01-29 20:10:53 -08:00
popover . sourceView = self . appDelegate . storyPagesViewController . view ;
2020-02-23 15:21:32 -08:00
[ self presentViewController : alert animated : YES completion : nil ] ;
} ] ;
} ] ;
} ] ;
2014-09-18 16:55:37 -07:00
}
- ( void ) showLinkContextMenu : ( CGPoint ) pt {
2020-08-27 15:08:46 -07:00
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'href');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * href , NSError * error ) {
[ self . webView evaluateJavaScript : [ NSString stringWithFormat : @ "linkAt(%li, %li, 'innerText');" , ( long ) pt . x , ( long ) pt . y ] completionHandler : ^ ( NSString * title , NSError * error ) {
2020-02-23 15:21:32 -08:00
NSURL * url = [ NSURL URLWithString : href ] ;
if ( ! href || ! [ href length ] ) return ;
NSValue * ptValue = [ NSValue valueWithCGPoint : pt ] ;
2021-01-29 20:10:53 -08:00
[ self . appDelegate showSendTo : self . appDelegate . storyPagesViewController
2020-02-23 15:21:32 -08:00
sender : ptValue
withUrl : url
authorName : nil
text : nil
title : title
feedTitle : nil
images : nil ] ;
} ] ;
} ] ;
2016-02-01 10:44:59 -08:00
}
- ( CGPoint ) pointForEvent : ( NSNotification * ) notification {
2021-01-29 20:10:53 -08:00
if ( self ! = appDelegate . storyPagesViewController . currentPage ) return CGPointZero ;
2016-02-01 10:44:59 -08:00
if ( ! self . view . window ) return CGPointZero ;
2014-09-17 19:02:12 -07:00
CGPoint pt ;
NSDictionary * coord = [ notification object ] ;
pt . x = [ [ coord objectForKey : @ "x" ] floatValue ] ;
pt . y = [ [ coord objectForKey : @ "y" ] floatValue ] ;
// convert point from window to view coordinate system
2016-02-01 10:44:59 -08:00
pt = [ webView convertPoint : pt fromView : nil ] ;
2014-09-17 19:02:12 -07:00
2016-02-01 10:44:59 -08:00
return pt ;
2014-09-18 18:25:38 -07:00
}
2016-02-01 10:44:59 -08:00
- ( CGPoint ) pointForGesture : ( UIGestureRecognizer * ) gestureRecognizer {
2021-01-29 20:10:53 -08:00
if ( self ! = appDelegate . storyPagesViewController . currentPage ) return CGPointZero ;
2016-02-01 10:44:59 -08:00
if ( ! self . view . window ) return CGPointZero ;
2014-09-18 18:25:38 -07:00
2021-01-29 20:10:53 -08:00
CGPoint pt = [ gestureRecognizer locationInView : appDelegate . storyPagesViewController . currentPage . webView ] ;
2014-09-18 18:25:38 -07:00
2016-02-01 10:44:59 -08:00
return pt ;
2014-09-17 19:02:12 -07:00
}
2017-04-11 15:43:42 -07:00
- ( void ) fetchImage : ( NSURL * ) url copy : ( BOOL ) copy save : ( BOOL ) save {
2014-09-18 15:15:41 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController showShareHUD : copy ?
2014-09-18 15:15:41 -07:00
@ "Copying..." : @ "Saving..." ] ;
2017-04-03 16:07:01 -07:00
AFHTTPSessionManager * manager = [ AFHTTPSessionManager manager ] ;
[ manager setResponseSerializer : [ AFImageResponseSerializer serializer ] ] ;
[ manager GET : url . absoluteString parameters : nil progress : nil success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2014-09-18 15:15:41 -07:00
UIImage * image = responseObject ;
2017-04-11 15:43:42 -07:00
if ( copy ) {
2014-09-18 15:15:41 -07:00
[ UIPasteboard generalPasteboard ] . image = image ;
[ self flashCheckmarkHud : @ "copied" ] ;
2018-07-13 15:25:27 -04:00
} else if ( save ) {
2017-04-11 15:43:42 -07:00
[ [ PHPhotoLibrary sharedPhotoLibrary ] performChanges : ^ {
PHAssetChangeRequest * changeRequest = [ PHAssetChangeRequest creationRequestForAssetFromImage : image ] ;
changeRequest . creationDate = [ NSDate date ] ;
} completionHandler : ^ ( BOOL success , NSError * _Nullable error ) {
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
if ( success ) {
[ self flashCheckmarkHud : @ "saved" ] ;
} else {
2017-04-11 16:15:18 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : NO ] ;
2017-04-11 15:43:42 -07:00
[ self informError : error ] ;
}
} ) ;
} ] ;
2014-09-18 15:15:41 -07:00
}
2017-04-03 16:07:01 -07:00
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
2014-09-18 15:15:41 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
[ self informError : @ "Could not fetch image" ] ;
} ] ;
}
2015-11-24 13:52:16 -05:00
- ( BOOL ) canPerformAction : ( SEL ) action withSender : ( id ) sender {
if ( [ self respondsToSelector : action ] )
return self . noStoryMessage . hidden ;
return [ super canPerformAction : action withSender : sender ] ;
}
2020-06-28 17:09:50 -07:00
# pragma mark -
2012-08-06 19:21:39 -07:00
# pragma mark Subscribing to blurblog
- ( void ) subscribeToBlurblog {
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController showShareHUD : @ "Following" ] ;
2013-06-18 21:23:20 -04:00
NSString * urlString = [ NSString stringWithFormat : @ "%@/social/follow" ,
2016-01-21 22:11:37 -08:00
self . appDelegate . url ] ;
2017-03-19 18:15:36 -07:00
NSMutableDictionary * params = [ NSMutableDictionary dictionary ] ;
2017-03-19 12:09:49 -07:00
[ params setObject : [ appDelegate . storiesCollection . activeFeed
2012-08-06 19:21:39 -07:00
objectForKey : @ "user_id" ]
forKey : @ "user_id" ] ;
2019-08-22 12:03:39 -07:00
[ appDelegate POST : urlString parameters : params success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2017-03-19 18:15:36 -07:00
[ self finishSubscribeToBlurblog : responseObject ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
2017-06-01 22:32:35 -07:00
NSHTTPURLResponse * httpResponse = ( NSHTTPURLResponse * ) task . response ;
[ self requestFailed : error statusCode : httpResponse . statusCode ] ;
2017-03-19 18:15:36 -07:00
} ] ;
}
2012-08-06 19:21:39 -07:00
2017-03-19 18:15:36 -07:00
- ( void ) finishSubscribeToBlurblog : ( NSDictionary * ) results {
2021-01-29 20:10:53 -08:00
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . view animated : NO ] ;
2014-09-18 15:15:41 -07:00
self . storyHUD = [ MBProgressHUD showHUDAddedTo : self . webView animated : YES ] ;
2012-08-06 19:21:39 -07:00
self . storyHUD . customView = [ [ UIImageView alloc ] initWithImage : [ UIImage imageNamed : @ "37x-Checkmark.png" ] ] ;
self . storyHUD . mode = MBProgressHUDModeCustomView ;
self . storyHUD . removeFromSuperViewOnHide = YES ;
self . storyHUD . labelText = @ "Followed" ;
[ self . storyHUD hide : YES afterDelay : 1 ] ;
2021-01-29 20:10:53 -08:00
appDelegate . storyPagesViewController . navigationItem . leftBarButtonItem = nil ;
2016-02-01 10:44:59 -08:00
[ appDelegate reloadFeedsView : NO ] ;
2012-08-07 09:57:21 -07:00
}
2012-08-06 19:21:39 -07:00
2012-07-30 14:58:57 -07:00
- ( void ) refreshComments : ( NSString * ) replyId {
2012-08-13 15:34:53 -07:00
NSString * shareBarString = [ self getShareBar ] ;
2012-08-07 11:27:00 -07:00
NSString * commentString = [ self getComments ] ;
2012-06-25 20:28:07 -07:00
NSString * jsString = [ [ NSString alloc ] initWithFormat : @
2012-08-13 15:34:53 -07:00
"document.getElementById('NB-comments-wrapper').innerHTML = '%@';"
2012-11-28 16:33:21 -08:00
"document.getElementById('NB-share-bar-wrapper').innerHTML = '%@';" ,
2012-08-13 15:34:53 -07:00
commentString ,
shareBarString ] ;
2016-02-01 10:44:59 -08:00
NSString * shareType = appDelegate . activeShareType ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : ^ ( id result , NSError * _Nullable error ) {
[ self . webView evaluateJavaScript : @ "attachFastClick();" completionHandler : ^ ( id result , NSError * _Nullable error ) {
// HACK to make the scroll event happen after the replace innerHTML event above happens .
dispatch_after ( dispatch_time ( DISPATCH_TIME _NOW , .15 * NSEC_PER _SEC ) ,
dispatch_get _main _queue ( ) , ^ {
if ( ! replyId ) {
NSString * currentUserId = [ NSString stringWithFormat : @ "%@" ,
2020-08-27 15:08:46 -07:00
[ self . appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
2020-02-23 15:21:32 -08:00
NSString * jsFlashString = [ [ NSString alloc ]
initWithFormat : @ "slideToComment('%@', true);" , currentUserId ] ;
[ self . webView evaluateJavaScript : jsFlashString completionHandler : ^ ( id result , NSError * _Nullable error ) {
[ self flashCheckmarkHud : shareType ] ;
2020-10-30 20:58:27 -07:00
[ self refreshSideOptions ] ;
2020-02-23 15:21:32 -08:00
} ] ;
} else if ( [ replyId isEqualToString : @ "like" ] ) {
} else {
NSString * jsFlashString = [ [ NSString alloc ]
initWithFormat : @ "slideToComment('%@', true);" , replyId ] ;
[ self . webView evaluateJavaScript : jsFlashString completionHandler : ^ ( id result , NSError * _Nullable error ) {
[ self flashCheckmarkHud : shareType ] ;
2020-10-30 20:58:27 -07:00
[ self refreshSideOptions ] ;
2020-02-23 15:21:32 -08:00
} ] ;
}
} ) ;
} ] ;
} ] ;
2012-12-18 17:29:23 -08:00
}
- ( void ) flashCheckmarkHud : ( NSString * ) messageType {
2014-09-18 15:15:41 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : NO ] ;
2021-01-29 20:10:53 -08:00
[ MBProgressHUD hideHUDForView : appDelegate . storyPagesViewController . currentPage . view animated : NO ] ;
2014-09-18 15:15:41 -07:00
self . storyHUD = [ MBProgressHUD showHUDAddedTo : self . webView animated : YES ] ;
2012-07-27 12:27:13 -07:00
self . storyHUD . customView = [ [ UIImageView alloc ] initWithImage : [ UIImage imageNamed : @ "37x-Checkmark.png" ] ] ;
self . storyHUD . mode = MBProgressHUDModeCustomView ;
2012-12-18 17:29:23 -08:00
self . storyHUD . removeFromSuperViewOnHide = YES ;
if ( [ messageType isEqualToString : @ "reply" ] ) {
2012-07-27 12:27:13 -07:00
self . storyHUD . labelText = @ "Replied" ;
2012-12-18 17:29:23 -08:00
} else if ( [ messageType isEqualToString : @ "edit-reply" ] ) {
2012-07-27 12:27:13 -07:00
self . storyHUD . labelText = @ "Edited Reply" ;
2012-12-18 17:29:23 -08:00
} else if ( [ messageType isEqualToString : @ "edit-share" ] ) {
2012-07-27 12:27:13 -07:00
self . storyHUD . labelText = @ "Edited Comment" ;
2012-12-18 17:29:23 -08:00
} else if ( [ messageType isEqualToString : @ "share" ] ) {
2012-07-27 12:27:13 -07:00
self . storyHUD . labelText = @ "Shared" ;
2012-12-18 17:29:23 -08:00
} else if ( [ messageType isEqualToString : @ "like-comment" ] ) {
2012-07-27 12:27:13 -07:00
self . storyHUD . labelText = @ "Favorited" ;
2012-12-18 17:29:23 -08:00
} else if ( [ messageType isEqualToString : @ "unlike-comment" ] ) {
2012-07-27 12:27:13 -07:00
self . storyHUD . labelText = @ "Unfavorited" ;
2012-12-18 17:29:23 -08:00
} else if ( [ messageType isEqualToString : @ "saved" ] ) {
self . storyHUD . labelText = @ "Saved" ;
} else if ( [ messageType isEqualToString : @ "unsaved" ] ) {
self . storyHUD . labelText = @ "No longer saved" ;
2012-12-19 15:37:36 -08:00
} else if ( [ messageType isEqualToString : @ "unread" ] ) {
self . storyHUD . labelText = @ "Unread" ;
2013-07-13 16:56:33 +02:00
} else if ( [ messageType isEqualToString : @ "added" ] ) {
self . storyHUD . labelText = @ "Added" ;
2014-09-18 15:15:41 -07:00
} else if ( [ messageType isEqualToString : @ "copied" ] ) {
self . storyHUD . labelText = @ "Copied" ;
} else if ( [ messageType isEqualToString : @ "saved" ] ) {
self . storyHUD . labelText = @ "Saved" ;
2012-07-27 12:27:13 -07:00
}
[ self . storyHUD hide : YES afterDelay : 1 ] ;
2012-07-12 13:34:41 -07:00
}
2015-11-21 23:23:37 -05:00
# pragma mark -
# pragma mark Scrolling
2012-07-30 14:58:57 -07:00
- ( void ) scrolltoComment {
2016-02-01 10:44:59 -08:00
NSString * currentUserId = [ NSString stringWithFormat : @ "%@" , [ appDelegate . dictSocialProfile objectForKey : @ "user_id" ] ] ;
2012-07-30 15:50:52 -07:00
NSString * jsFlashString = [ [ NSString alloc ] initWithFormat : @ "slideToComment('%@', true);" , currentUserId ] ;
2023-04-19 14:10:09 -07:00
if ( [ self getComments ] . length ) {
[ self . webView evaluateJavaScript : jsFlashString completionHandler : nil ] ;
}
2012-06-25 20:28:07 -07:00
}
2015-11-21 23:23:37 -05:00
- ( void ) tryScrollingDown : ( BOOL ) down {
2016-02-01 10:44:59 -08:00
UIScrollView * scrollView = webView . scrollView ;
2015-11-21 23:23:37 -05:00
CGPoint contentOffset = scrollView . contentOffset ;
CGFloat frameHeight = scrollView . frame . size . height ;
CGFloat scrollHeight = frameHeight - 45 ; // ~ height of source bar and buttons
if ( down ) {
CGSize contentSize = scrollView . contentSize ;
if ( contentOffset . y + frameHeight = = contentSize . height )
return ;
contentOffset . y = MIN ( contentOffset . y + scrollHeight , contentSize . height - frameHeight ) ;
} else {
if ( contentOffset . y <= 0 )
return ;
contentOffset . y = MAX ( contentOffset . y - scrollHeight , 0 ) ;
}
[ scrollView setContentOffset : contentOffset animated : YES ] ;
}
- ( void ) scrollPageDown : ( id ) sender {
[ self tryScrollingDown : YES ] ;
}
- ( void ) scrollPageUp : ( id ) sender {
[ self tryScrollingDown : NO ] ;
}
2012-11-05 17:16:10 -08:00
- ( NSString * ) textToHtml : ( NSString * ) htmlString {
htmlString = [ htmlString stringByReplacingOccurrencesOfString : @ "'" withString : @ "'" ] ;
htmlString = [ htmlString stringByReplacingOccurrencesOfString : @ "\n" withString : @ "<br/>" ] ;
return htmlString ;
2011-06-14 10:35:33 -04:00
}
2012-11-07 17:54:16 -08:00
- ( void ) changeWebViewWidth {
2016-11-01 15:10:56 -07:00
// Don ' t do this in the background , to avoid scrolling to the top unnecessarily
if ( [ UIApplication sharedApplication ] . applicationState = = UIApplicationStateBackground ) {
return ;
}
2016-02-01 10:44:59 -08:00
// NSLog ( @ "changeWebViewWidth: %@ / %@ / %@" , NSStringFromCGSize ( self . view . bounds . size ) , NSStringFromCGSize ( webView . scrollView . bounds . size ) , NSStringFromCGSize ( webView . scrollView . contentSize ) ) ;
2015-09-23 11:34:03 -07:00
2016-02-01 10:44:59 -08:00
NSInteger contentWidth = CGRectGetWidth ( webView . scrollView . bounds ) ;
2012-06-28 11:12:38 -07:00
NSString * contentWidthClass ;
2014-09-19 17:25:57 -07:00
2020-03-29 16:21:00 -07:00
# if TARGET_OS _MACCATALYST
// CATALYST : probably will want to add custom CSS for Macs .
contentWidthClass = @ "NB-ipad-wide NB-ipad-pro-12-wide NB-width-768" ;
# else
2020-11-23 20:31:36 -08:00
UIInterfaceOrientation orientation = self . view . window . windowScene . interfaceOrientation ;
2015-11-28 22:07:38 -08:00
if ( UIInterfaceOrientationIsLandscape ( orientation ) && ! self . isPhoneOrCompact ) {
2017-11-01 21:51:56 -07:00
if ( iPadPro12 ) {
contentWidthClass = @ "NB-ipad-wide NB-ipad-pro-12-wide" ;
} else if ( iPadPro10 ) {
contentWidthClass = @ "NB-ipad-wide NB-ipad-pro-10-wide" ;
2016-04-06 18:14:06 -07:00
} else {
contentWidthClass = @ "NB-ipad-wide" ;
}
2015-11-28 22:07:38 -08:00
} else if ( ! UIInterfaceOrientationIsLandscape ( orientation ) && ! self . isPhoneOrCompact ) {
2017-11-01 21:51:56 -07:00
if ( iPadPro12 ) {
contentWidthClass = @ "NB-ipad-narrow NB-ipad-pro-12-narrow" ;
} else if ( iPadPro10 ) {
contentWidthClass = @ "NB-ipad-narrow NB-ipad-pro-10-narrow" ;
2016-04-06 18:14:06 -07:00
} else {
contentWidthClass = @ "NB-ipad-narrow" ;
}
2015-11-28 22:07:38 -08:00
} else if ( UIInterfaceOrientationIsLandscape ( orientation ) && self . isPhoneOrCompact ) {
2014-09-19 17:25:57 -07:00
contentWidthClass = @ "NB-iphone-wide" ;
2012-06-28 11:12:38 -07:00
} else {
contentWidthClass = @ "NB-iphone" ;
}
2014-09-19 17:25:57 -07:00
2020-03-29 16:21:00 -07:00
contentWidthClass = [ NSString stringWithFormat : @ "%@ NB-width-%d" ,
contentWidthClass , ( int ) floorf ( CGRectGetWidth ( webView . scrollView . bounds ) ) ] ;
# endif
2017-05-11 12:51:40 -07:00
NSString * alternateViewClass = @ "" ;
if ( ! self . isPhoneOrCompact ) {
2021-05-25 16:20:16 -04:00
if ( ! appDelegate . detailViewController . storyTitlesOnLeft ) {
2017-05-11 12:51:40 -07:00
alternateViewClass = @ "NB-titles-bottom" ;
} else {
alternateViewClass = @ "NB-titles-left" ;
}
}
2016-02-01 10:44:59 -08:00
NSString * riverClass = ( appDelegate . storiesCollection . isRiverView ||
appDelegate . storiesCollection . isSocialView ||
appDelegate . storiesCollection . isSavedView ||
2022-03-09 19:16:43 -07:00
appDelegate . storiesCollection . isWidgetView ||
2016-02-01 10:44:59 -08:00
appDelegate . storiesCollection . isReadView ) ?
2013-03-13 14:05:58 -07:00
@ "NB-river" : @ "NB-non-river" ;
2012-06-28 11:12:38 -07:00
2012-07-12 13:34:41 -07:00
NSString * jsString = [ [ NSString alloc ] initWithFormat :
2017-05-11 12:51:40 -07:00
@ "$('body').attr('class', '%@ %@ %@');"
2015-09-23 11:34:03 -07:00
"document.getElementById(\" viewport \ ").setAttribute(\" content \ ", \" width = % li ; initial - scale = 1 ; minimum - scale = 1.0 ; maximum - scale = 1.0 ; user - scalable = 0 ; \ ");" ,
2012-07-16 10:10:52 -07:00
contentWidthClass ,
2017-05-11 12:51:40 -07:00
alternateViewClass ,
2013-03-13 14:05:58 -07:00
riverClass ,
2015-09-22 13:10:35 -07:00
( long ) contentWidth ] ;
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : nil ] ;
2012-06-27 21:28:04 -07:00
}
2012-12-07 17:18:31 -08:00
- ( void ) refreshHeader {
2012-12-13 12:40:05 -08:00
NSString * headerString = [ [ [ self getHeader ] stringByReplacingOccurrencesOfString : @ "\'" withString : @ "\\'" ]
2014-05-21 12:24:22 -07:00
stringByReplacingOccurrencesOfString : @ "\n" withString : @ " " ] ;
2012-12-07 17:18:31 -08:00
NSString * jsString = [ NSString stringWithFormat : @ "document.getElementById('NB-header-container').innerHTML = '%@';" ,
headerString ] ;
2014-05-21 12:24:22 -07:00
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : ^ ( id result , NSError * error ) {
[ self . webView evaluateJavaScript : @ "attachFastClick();" completionHandler : nil ] ;
} ] ;
2014-05-21 12:24:22 -07:00
}
2012-12-13 12:40:05 -08:00
2020-10-30 20:58:27 -07:00
- ( void ) refreshSideOptions {
NSString * sideOptionsString = [ [ [ self getSideOptions ] stringByReplacingOccurrencesOfString : @ "\'" withString : @ "\\'" ]
2014-05-21 12:24:22 -07:00
stringByReplacingOccurrencesOfString : @ "\n" withString : @ " " ] ;
NSString * jsString = [ NSString stringWithFormat : @ "document.getElementById('NB-sideoptions-container').innerHTML = '%@';" ,
2020-10-30 20:58:27 -07:00
sideOptionsString ] ;
2014-05-21 12:24:22 -07:00
2020-02-23 15:21:32 -08:00
[ self . webView evaluateJavaScript : jsString completionHandler : ^ ( id result , NSError * error ) {
[ self . webView evaluateJavaScript : @ "attachFastClick();" completionHandler : nil ] ;
} ] ;
2012-12-07 17:18:31 -08:00
}
2013-05-28 18:07:19 -07:00
# pragma mark -
# pragma mark Text view
2015-10-05 11:45:33 -07:00
- ( void ) showTextOrStoryView {
NSString * feedIdStr = [ NSString stringWithFormat : @ "%@" ,
[ self . activeStory objectForKey : @ "story_feed_id" ] ] ;
2016-02-01 10:44:59 -08:00
if ( [ appDelegate isFeedInTextView : feedIdStr ] ) {
2015-10-05 11:45:33 -07:00
if ( ! self . inTextView ) {
[ self fetchTextView ] ;
}
} else {
if ( self . inTextView ) {
[ self showStoryView ] ;
}
}
}
2015-11-21 23:23:37 -05:00
- ( void ) toggleTextView : ( id ) sender {
if ( self . inTextView )
[ self showStoryView ] ;
else
[ self fetchTextView ] ;
}
2015-03-10 18:58:23 -07:00
- ( void ) showStoryView {
self . inTextView = NO ;
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController setTextButton : ( StoryDetailViewController * ) self ] ;
2015-03-10 18:58:23 -07:00
[ self drawStory ] ;
}
2013-05-28 18:07:19 -07:00
- ( void ) fetchTextView {
2015-03-09 14:20:45 -07:00
if ( ! self . activeStoryId || ! self . activeStory ) return ;
2015-03-10 18:58:23 -07:00
self . inTextView = YES ;
2015-03-12 19:43:39 -07:00
// NSLog ( @ "Fetching Text: %@" , [ self . activeStory objectForKey : @ "story_title" ] ) ;
2021-01-29 20:10:53 -08:00
if ( self . activeStory = = appDelegate . storyPagesViewController . currentPage . activeStory ) {
[ self . appDelegate . storyPagesViewController showFetchingTextNotifier ] ;
2015-11-30 18:12:10 -08:00
}
2017-03-24 17:30:46 -07:00
NSString * storyId = [ self . activeStory objectForKey : @ "id" ] ;
2019-10-25 20:52:51 -07:00
[ appDelegate fetchTextForStory : [ self . activeStory objectForKey : @ "story_hash" ] inFeed : [ self . activeStory objectForKey : @ "story_feed_id" ] checkCache : YES withCallback : ^ ( NSString * text ) {
if ( text ! = nil ) {
[ self finishFetchText : text storyId : storyId ] ;
} else {
[ self failedFetchText ] ;
}
2017-03-24 17:30:46 -07:00
} ] ;
2013-05-28 18:07:19 -07:00
}
2019-10-25 20:52:51 -07:00
- ( void ) failedFetchText {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideNotifier ] ;
2015-03-10 18:58:23 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
2021-01-29 20:10:53 -08:00
if ( self . activeStory = = appDelegate . storyPagesViewController . currentPage . activeStory ) {
2015-11-30 18:12:10 -08:00
[ self informError : @ "Could not fetch text" ] ;
}
2015-03-10 18:58:23 -07:00
self . inTextView = NO ;
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController setTextButton : ( StoryDetailViewController * ) self ] ;
2015-03-10 18:58:23 -07:00
}
2013-05-28 18:07:19 -07:00
2019-10-25 20:52:51 -07:00
- ( void ) finishFetchText : ( NSString * ) text storyId : ( NSString * ) storyId {
2017-03-24 17:30:46 -07:00
if ( ! [ storyId isEqualToString : [ self . activeStory objectForKey : @ "id" ] ] ) {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideNotifier ] ;
2013-10-17 11:21:37 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
self . inTextView = NO ;
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController setTextButton : ( StoryDetailViewController * ) self ] ;
2013-10-17 11:21:37 -07:00
return ;
}
2015-03-10 18:58:23 -07:00
NSMutableDictionary * newActiveStory = [ self . activeStory mutableCopy ] ;
2019-10-25 20:52:51 -07:00
[ newActiveStory setObject : text forKey : @ "original_text" ] ;
2016-02-01 10:44:59 -08:00
if ( [ [ self . activeStory objectForKey : @ "story_hash" ] isEqualToString : [ appDelegate . activeStory objectForKey : @ "story_hash" ] ] ) {
appDelegate . activeStory = newActiveStory ;
2015-09-22 17:15:50 -07:00
}
2015-03-10 18:58:23 -07:00
self . activeStory = newActiveStory ;
2013-05-28 18:07:19 -07:00
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideNotifier ] ;
2013-05-28 18:07:19 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
2013-05-29 13:36:39 -07:00
self . inTextView = YES ;
2015-03-10 18:58:23 -07:00
[ self drawStory ] ;
2015-03-12 19:43:39 -07:00
// NSLog ( @ "Fetched Text: %@" , [ self . activeStory objectForKey : @ "story_title" ] ) ;
2013-05-28 18:07:19 -07:00
}
2019-06-19 20:45:30 -07:00
- ( void ) fetchStoryChanges {
if ( ! self . activeStoryId || ! self . activeStory ) return ;
self . inTextView = YES ;
// NSLog ( @ "Fetching Changes: %@" , [ self . activeStory objectForKey : @ "story_title" ] ) ;
2021-01-29 20:10:53 -08:00
if ( self . activeStory = = appDelegate . storyPagesViewController . currentPage . activeStory ) {
2019-06-19 20:45:30 -07:00
dispatch_async ( dispatch_get _main _queue ( ) , ^ {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController showFetchingTextNotifier ] ;
2019-06-19 20:45:30 -07:00
} ) ;
}
NSString * urlString = [ NSString stringWithFormat : @ "%@/rss_feeds/story_changes" ,
self . appDelegate . url ] ;
NSMutableDictionary * params = [ NSMutableDictionary dictionary ] ;
[ params setObject : [ self . activeStory objectForKey : @ "story_hash" ] forKey : @ "story_hash" ] ;
[ params setObject : @ "true" forKey : @ "show_changes" ] ;
NSString * storyId = [ self . activeStory objectForKey : @ "id" ] ;
2022-01-24 16:35:27 -08:00
[ appDelegate GET : urlString parameters : params success : ^ ( NSURLSessionDataTask * _Nonnull task , id _Nullable responseObject ) {
2019-06-19 20:45:30 -07:00
[ self finishFetchStoryChanges : responseObject storyId : storyId ] ;
} failure : ^ ( NSURLSessionDataTask * _Nullable task , NSError * _Nonnull error ) {
[ self failedFetchStoryChanges : error ] ;
} ] ;
}
- ( void ) failedFetchStoryChanges : ( NSError * ) error {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideNotifier ] ;
2019-06-19 20:45:30 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
2021-01-29 20:10:53 -08:00
if ( self . activeStory = = appDelegate . storyPagesViewController . currentPage . activeStory ) {
2019-06-19 20:45:30 -07:00
[ self informError : @ "Could not fetch changes" ] ;
}
self . inTextView = NO ;
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController setTextButton : ( StoryDetailViewController * ) self ] ;
2019-06-19 20:45:30 -07:00
}
- ( void ) finishFetchStoryChanges : ( NSDictionary * ) results storyId : ( NSString * ) storyId {
if ( [ results [ @ "failed" ] boolValue ] ) {
2019-10-25 20:52:51 -07:00
[ self failedFetchText ] ;
2019-06-19 20:45:30 -07:00
return ;
}
if ( ! [ storyId isEqualToString : self . activeStory [ @ "id" ] ] ) {
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideNotifier ] ;
2019-06-19 20:45:30 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
self . inTextView = NO ;
2021-01-29 20:10:53 -08:00
[ appDelegate . storyPagesViewController setTextButton : ( StoryDetailViewController * ) self ] ;
2019-06-19 20:45:30 -07:00
return ;
}
NSMutableDictionary * newActiveStory = [ self . activeStory mutableCopy ] ;
NSDictionary * resultsStory = results [ @ "story" ] ;
newActiveStory [ @ "story_changes" ] = resultsStory [ @ "story_content" ] ;
if ( [ self . activeStory [ @ "story_hash" ] isEqualToString : appDelegate . activeStory [ @ "story_hash" ] ] ) {
appDelegate . activeStory = newActiveStory ;
}
self . activeStory = newActiveStory ;
2021-01-29 20:10:53 -08:00
[ self . appDelegate . storyPagesViewController hideNotifier ] ;
2019-06-19 20:45:30 -07:00
[ MBProgressHUD hideHUDForView : self . webView animated : YES ] ;
self . inTextView = YES ;
[ self drawStory ] ;
// NSLog ( @ "Fetched Changes: %@" , self . activeStory [ @ "story_title" ] ) ;
}
2013-05-28 18:07:19 -07:00
2010-06-25 18:36:01 -04:00
@ end