mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
Implemented #769 (Safari swipe to dismiss)
This commit is contained in:
parent
da5c895eea
commit
ff42d673c2
9 changed files with 216 additions and 5 deletions
|
@ -12,7 +12,7 @@
|
|||
@class NewsBlurAppDelegate;
|
||||
|
||||
@interface NBContainerViewController : UIViewController
|
||||
<UIPopoverControllerDelegate, SFSafariViewControllerDelegate> {
|
||||
<UIPopoverControllerDelegate, SFSafariViewControllerDelegate, UIViewControllerTransitioningDelegate> {
|
||||
NewsBlurAppDelegate *appDelegate;
|
||||
|
||||
BOOL interactiveOriginalTransition;
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
#import "OriginalStoryViewController.h"
|
||||
#import "ShareViewController.h"
|
||||
#import "UserProfileViewController.h"
|
||||
#import "NBSafariViewController.h"
|
||||
#import "NBModalPushPopTransition.h"
|
||||
#import "InteractionCell.h"
|
||||
#import "ActivityCell.h"
|
||||
#import "FeedTableCell.h"
|
||||
|
@ -48,7 +50,8 @@
|
|||
@property (nonatomic, strong) OriginalStoryViewController *originalViewController;
|
||||
@property (nonatomic, strong) StoryPageControl *storyPageControl;
|
||||
@property (nonatomic, strong) ShareViewController *shareViewController;
|
||||
@property (nonatomic, strong) SFSafariViewController *safariViewController;
|
||||
@property (nonatomic, strong) NBSafariViewController *safariViewController;
|
||||
@property (nonatomic, strong) NBModalPushPopTransition *safariAnimator;
|
||||
@property (nonatomic, strong) UIView *storyTitlesStub;
|
||||
@property (readwrite) BOOL storyTitlesOnLeft;
|
||||
@property (readwrite) int storyTitlesYCoordinate;
|
||||
|
@ -715,11 +718,17 @@
|
|||
}
|
||||
|
||||
- (void)transitionToSafariView:(NSURL *)url {
|
||||
self.safariViewController = [[SFSafariViewController alloc] initWithURL:url
|
||||
self.safariAnimator = [NBModalPushPopTransition new];
|
||||
self.safariViewController = [[NBSafariViewController alloc] initWithURL:url
|
||||
entersReaderIfAvailable:NO];
|
||||
self.safariViewController.delegate = self;
|
||||
self.safariViewController.transitioningDelegate = self;
|
||||
// self.navigationController.navigationBar.translucent = YES;
|
||||
[self.storyNavigationController presentViewController:self.safariViewController animated:YES completion:nil];
|
||||
[self.storyNavigationController presentViewController:self.safariViewController animated:YES completion:^{
|
||||
UIScreenEdgePanGestureRecognizer *recognizer = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)];
|
||||
recognizer.edges = UIRectEdgeLeft;
|
||||
[self.safariViewController.edgeView addGestureRecognizer:recognizer];
|
||||
}];
|
||||
// [self.storyNavigationController pushViewController:self.safariViewController animated:YES];
|
||||
}
|
||||
|
||||
|
@ -729,6 +738,41 @@
|
|||
[controller dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void)handleGesture:(UIScreenEdgePanGestureRecognizer *)recognizer {
|
||||
self.safariAnimator.percentageDriven = YES;
|
||||
CGFloat percentComplete = [recognizer locationInView:self.view].x / self.view.bounds.size.width / 2.0;
|
||||
|
||||
switch (recognizer.state) {
|
||||
case UIGestureRecognizerStateBegan:
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
break;
|
||||
case UIGestureRecognizerStateChanged:
|
||||
[self.safariAnimator updateInteractiveTransition:percentComplete > 0.99 ? 0.99 : percentComplete];
|
||||
break;
|
||||
case UIGestureRecognizerStateEnded:
|
||||
case UIGestureRecognizerStateCancelled:
|
||||
([recognizer velocityInView:self.view].x < 0.0) ? [self.safariAnimator cancelInteractiveTransition] : [self.safariAnimator finishInteractiveTransition];
|
||||
self.safariAnimator.percentageDriven = NO;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source {
|
||||
self.safariAnimator.dismissing = NO;
|
||||
return self.safariAnimator;
|
||||
}
|
||||
|
||||
- (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed {
|
||||
self.safariAnimator.dismissing = YES;
|
||||
return self.safariAnimator;
|
||||
}
|
||||
|
||||
- (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator {
|
||||
return self.safariAnimator.percentageDriven ? self.safariAnimator : nil;
|
||||
}
|
||||
|
||||
- (void)transitionToOriginalView {
|
||||
[self transitionToOriginalView:YES];
|
||||
}
|
||||
|
|
17
clients/ios/Classes/NBModalPushPopTransition.h
Normal file
17
clients/ios/Classes/NBModalPushPopTransition.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
//
|
||||
// NBModalPushPopTransition.h
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2015-10-23.
|
||||
// Copyright © 2015 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface NBModalPushPopTransition : UIPercentDrivenInteractiveTransition <UIViewControllerAnimatedTransitioning>
|
||||
|
||||
@property (nonatomic) BOOL dismissing;
|
||||
@property (nonatomic) BOOL percentageDriven;
|
||||
|
||||
@end
|
||||
|
75
clients/ios/Classes/NBModalPushPopTransition.m
Normal file
75
clients/ios/Classes/NBModalPushPopTransition.m
Normal file
|
@ -0,0 +1,75 @@
|
|||
//
|
||||
// NBModalPushPopTransition.m
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2015-10-23.
|
||||
// Copyright © 2015 NewsBlur. All rights reserved.
|
||||
//
|
||||
// Based on Swift code from https://github.com/stringcode86/SCSafariViewController
|
||||
//
|
||||
|
||||
#import "NBModalPushPopTransition.h"
|
||||
|
||||
@implementation NBModalPushPopTransition
|
||||
|
||||
- (id)init {
|
||||
if ((self = [super init])) {
|
||||
self.dismissing = NO;
|
||||
self.percentageDriven = NO;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (CGFloat)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext {
|
||||
return 0.75;
|
||||
}
|
||||
|
||||
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
|
||||
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
|
||||
UIView *topView = self.dismissing ? fromViewController.view : toViewController.view;
|
||||
UIViewController *bottomViewController = self.dismissing ? toViewController : fromViewController;
|
||||
UIView *bottomView = bottomViewController.view;
|
||||
CGFloat offset = bottomView.bounds.size.width;
|
||||
|
||||
if ([bottomViewController isKindOfClass:[UINavigationController class]]) {
|
||||
bottomView = ((UINavigationController *)bottomViewController).topViewController.view;
|
||||
}
|
||||
|
||||
[transitionContext.containerView insertSubview:toViewController.view aboveSubview:fromViewController.view];
|
||||
|
||||
if (self.dismissing) {
|
||||
[transitionContext.containerView insertSubview:toViewController.view belowSubview:fromViewController.view];
|
||||
}
|
||||
|
||||
topView.frame = fromViewController.view.frame;
|
||||
topView.transform = self.dismissing ? CGAffineTransformIdentity : CGAffineTransformMakeTranslation(offset, 0.0);
|
||||
|
||||
UIImageView *shadowView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"safari_shadow"]];
|
||||
|
||||
shadowView.contentMode = UIViewContentModeScaleAspectFill;
|
||||
shadowView.layer.anchorPoint = CGPointMake(0.0, 0.5);
|
||||
shadowView.frame = bottomView.bounds;
|
||||
[bottomView addSubview:shadowView];
|
||||
shadowView.transform = self.dismissing ? CGAffineTransformMakeScale(0.01, 1.0) : CGAffineTransformIdentity;
|
||||
shadowView.alpha = self.dismissing ? 1.0 : 0.0;
|
||||
|
||||
[UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 usingSpringWithDamping:0.9 initialSpringVelocity:1.0 options:self.animationOpts animations:^{
|
||||
topView.transform = self.dismissing ? CGAffineTransformMakeTranslation(offset, 0.0) : CGAffineTransformIdentity;
|
||||
shadowView.transform = self.dismissing ? CGAffineTransformIdentity : CGAffineTransformMakeScale(0.01, 1.0);
|
||||
shadowView.alpha = self.dismissing ? 0.0 : 1.0;
|
||||
} completion:^(BOOL finished) {
|
||||
topView.transform = CGAffineTransformIdentity;
|
||||
[shadowView removeFromSuperview];
|
||||
[transitionContext completeTransition:!transitionContext.transitionWasCancelled];
|
||||
}];
|
||||
}
|
||||
|
||||
- (UIViewAnimationOptions)animationOpts {
|
||||
return UIViewAnimationOptionAllowAnimatedContent | UIViewAnimationOptionBeginFromCurrentState | UIViewAnimationOptionLayoutSubviews;
|
||||
}
|
||||
|
||||
@end
|
||||
|
16
clients/ios/Classes/NBSafariViewController.h
Normal file
16
clients/ios/Classes/NBSafariViewController.h
Normal file
|
@ -0,0 +1,16 @@
|
|||
//
|
||||
// NBSafariViewController.h
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2015-10-23.
|
||||
// Copyright © 2015 NewsBlur. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SafariServices/SafariServices.h>
|
||||
|
||||
@interface NBSafariViewController : SFSafariViewController
|
||||
|
||||
@property (nonatomic, strong, readonly) UIView *edgeView;
|
||||
|
||||
@end
|
||||
|
42
clients/ios/Classes/NBSafariViewController.m
Normal file
42
clients/ios/Classes/NBSafariViewController.m
Normal file
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// NBSafariViewController.m
|
||||
// NewsBlur
|
||||
//
|
||||
// Created by David Sinclair on 2015-10-23.
|
||||
// Copyright © 2015 NewsBlur. All rights reserved.
|
||||
//
|
||||
// Based on Swift code from https://github.com/stringcode86/SCSafariViewController
|
||||
//
|
||||
|
||||
#import "NBSafariViewController.h"
|
||||
|
||||
@interface NBSafariViewController ()
|
||||
|
||||
@property (nonatomic, strong) UIView *edgeView;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@implementation NBSafariViewController
|
||||
|
||||
- (UIView *)edgeView {
|
||||
if (_edgeView == nil && self.isViewLoaded) {
|
||||
self.edgeView = [UIView new];
|
||||
_edgeView.translatesAutoresizingMaskIntoConstraints = NO;
|
||||
[self.view addSubview:_edgeView];
|
||||
_edgeView.backgroundColor = [UIColor colorWithWhite:1.0 alpha:0.005];
|
||||
|
||||
NSDictionary *bindings = @{@"edgeView" : _edgeView};
|
||||
NSLayoutFormatOptions options = 0;
|
||||
NSArray *hConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[edgeView(5)]" options:options metrics:nil views:bindings];
|
||||
NSArray *vConstraints = [NSLayoutConstraint constraintsWithVisualFormat:@"V:|-0-[edgeView]-0-|" options:options metrics:nil views:bindings];
|
||||
|
||||
[NSLayoutConstraint activateConstraints:hConstraints];
|
||||
[NSLayoutConstraint activateConstraints:vConstraints];
|
||||
}
|
||||
|
||||
return _edgeView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#import "ARChromeActivity.h"
|
||||
#import "NBCopyLinkActivity.h"
|
||||
#import "MBProgressHUD.h"
|
||||
#import "NBSafariViewController.h"
|
||||
#import "Utilities.h"
|
||||
#import "StringHelper.h"
|
||||
#import "AuthorizeServicesViewController.h"
|
||||
|
@ -1326,7 +1327,7 @@
|
|||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
[self.masterContainerViewController transitionToSafariView:url];
|
||||
} else {
|
||||
SFSafariViewController *safari = [[SFSafariViewController alloc] initWithURL:url
|
||||
NBSafariViewController *safari = [[NBSafariViewController alloc] initWithURL:url
|
||||
entersReaderIfAvailable:NO];
|
||||
safari.delegate = self;
|
||||
[navigationController pushViewController:safari animated:YES];
|
||||
|
|
|
@ -9,6 +9,9 @@
|
|||
/* Begin PBXBuildFile section */
|
||||
010EDEFA1B2386B7003B79DE /* OnePasswordExtension.m in Sources */ = {isa = PBXBuildFile; fileRef = 010EDEF81B2386B7003B79DE /* OnePasswordExtension.m */; };
|
||||
010EDEFC1B238722003B79DE /* 1Password.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 010EDEFB1B238722003B79DE /* 1Password.xcassets */; };
|
||||
17F1566C1BDAB0930092EBFD /* NBSafariViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F1566B1BDAB0930092EBFD /* NBSafariViewController.m */; settings = {ASSET_TAGS = (); }; };
|
||||
17F1566F1BDAB14F0092EBFD /* NBModalPushPopTransition.m in Sources */ = {isa = PBXBuildFile; fileRef = 17F1566E1BDAB14F0092EBFD /* NBModalPushPopTransition.m */; settings = {ASSET_TAGS = (); }; };
|
||||
17F156711BDABBF60092EBFD /* safari_shadow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 17F156701BDABBF60092EBFD /* safari_shadow@2x.png */; settings = {ASSET_TAGS = (); }; };
|
||||
1D3623260D0F684500981E51 /* NewsBlurAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* NewsBlurAppDelegate.m */; };
|
||||
1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; };
|
||||
1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; };
|
||||
|
@ -455,6 +458,11 @@
|
|||
010EDEF81B2386B7003B79DE /* OnePasswordExtension.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OnePasswordExtension.m; path = "Other Sources/OnePasswordExtension/OnePasswordExtension.m"; sourceTree = "<group>"; };
|
||||
010EDEF91B2386B7003B79DE /* OnePasswordExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OnePasswordExtension.h; path = "Other Sources/OnePasswordExtension/OnePasswordExtension.h"; sourceTree = "<group>"; };
|
||||
010EDEFB1B238722003B79DE /* 1Password.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = 1Password.xcassets; path = "Other Sources/OnePasswordExtension/1Password.xcassets"; sourceTree = "<group>"; };
|
||||
17F1566A1BDAB0930092EBFD /* NBSafariViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBSafariViewController.h; sourceTree = "<group>"; };
|
||||
17F1566B1BDAB0930092EBFD /* NBSafariViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBSafariViewController.m; sourceTree = "<group>"; };
|
||||
17F1566D1BDAB14F0092EBFD /* NBModalPushPopTransition.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NBModalPushPopTransition.h; sourceTree = "<group>"; };
|
||||
17F1566E1BDAB14F0092EBFD /* NBModalPushPopTransition.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NBModalPushPopTransition.m; sourceTree = "<group>"; };
|
||||
17F156701BDABBF60092EBFD /* safari_shadow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "safari_shadow@2x.png"; sourceTree = "<group>"; };
|
||||
1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
|
||||
1D3623240D0F684500981E51 /* NewsBlurAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = NewsBlurAppDelegate.h; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; };
|
||||
1D3623250D0F684500981E51 /* NewsBlurAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = NewsBlurAppDelegate.m; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.objc; };
|
||||
|
@ -1546,6 +1554,7 @@
|
|||
FFEA5AEB19D340BC00ED87A0 /* logo_newsblur_512.png */,
|
||||
43A4C42415B00A26008787B5 /* logo_background.png */,
|
||||
43A4C42615B00A26008787B5 /* logo_newsblur_blur.png */,
|
||||
17F156701BDABBF60092EBFD /* safari_shadow@2x.png */,
|
||||
43A4C43F15B00A26008787B5 /* warning.gif */,
|
||||
43A4C44015B00A26008787B5 /* warning.png */,
|
||||
43A4C44115B00A26008787B5 /* world.png */,
|
||||
|
@ -1774,6 +1783,10 @@
|
|||
FFA0483D19CA5B8400618DC4 /* EventWindow.m */,
|
||||
FF1C4E151A3FB1F4000995E3 /* NBActivityItemProvider.h */,
|
||||
FF1C4E161A3FB1F4000995E3 /* NBActivityItemProvider.m */,
|
||||
17F1566D1BDAB14F0092EBFD /* NBModalPushPopTransition.h */,
|
||||
17F1566E1BDAB14F0092EBFD /* NBModalPushPopTransition.m */,
|
||||
17F1566A1BDAB0930092EBFD /* NBSafariViewController.h */,
|
||||
17F1566B1BDAB0930092EBFD /* NBSafariViewController.m */,
|
||||
);
|
||||
name = Foundation;
|
||||
sourceTree = "<group>";
|
||||
|
@ -2288,6 +2301,7 @@
|
|||
FF3964BC192BED0A004BEE1A /* tag.png in Resources */,
|
||||
FF29708B16DD7AA400E92F85 /* segment_active.png in Resources */,
|
||||
FF29708C16DD7AA400E92F85 /* segment_inactive.png in Resources */,
|
||||
17F156711BDABBF60092EBFD /* safari_shadow@2x.png in Resources */,
|
||||
FF29708E16DD7C8A00E92F85 /* segment_left_selected.png in Resources */,
|
||||
FF29709016DD7FD800E92F85 /* segment_unselected.png in Resources */,
|
||||
FF03B00319F881380063002A /* ARChromeActivity~ipad.png in Resources */,
|
||||
|
@ -2484,6 +2498,7 @@
|
|||
FF5EA47F143B691000B7563D /* AddSiteViewController.m in Sources */,
|
||||
FF1F13D818AAC97900FDA816 /* UIImage+Resize.m in Sources */,
|
||||
FFD887F01445F1E800385399 /* AddSiteAutocompleteCell.m in Sources */,
|
||||
17F1566F1BDAB14F0092EBFD /* NBModalPushPopTransition.m in Sources */,
|
||||
FF62820A1A098EA800271FDB /* WYPopoverController.m in Sources */,
|
||||
FF8D1ECD1BAA311000725D8A /* SBJson4StreamParser.m in Sources */,
|
||||
FFE5322F144C8AC300ACFDE0 /* Utilities.m in Sources */,
|
||||
|
@ -2532,6 +2547,7 @@
|
|||
FF2EB7BE1AA65504002549A7 /* IASKTextField.m in Sources */,
|
||||
FF8D1ECF1BAA311000725D8A /* SBJson4StreamTokeniser.m in Sources */,
|
||||
FFD660641BACA46D006E4B8D /* AFNetworkReachabilityManager.m in Sources */,
|
||||
17F1566C1BDAB0930092EBFD /* NBSafariViewController.m in Sources */,
|
||||
FF8D1ED81BAA33BA00725D8A /* NSObject+SBJSON.m in Sources */,
|
||||
FF2EB7B11AA65504002549A7 /* IASKAppSettingsWebViewController.m in Sources */,
|
||||
FF1F13D418A9C2BE00FDA816 /* TMDiskCache.m in Sources */,
|
||||
|
|
BIN
clients/ios/Resources/safari_shadow@2x.png
Normal file
BIN
clients/ios/Resources/safari_shadow@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 19 KiB |
Loading…
Add table
Reference in a new issue