NewsBlur/clients/ios/Classes/DetailObjCViewController.m

1870 lines
78 KiB
Mathematica
Raw Normal View History

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