diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..522e0cf --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "SVWebViewController/vendors/OpenInChromeController"] + path = SVWebViewController/vendors/OpenInChromeController +url=https://github.com/adonoho/OpenInChrome.git diff --git a/SVWebViewController/SVModalWebViewController.h b/SVWebViewController/SVModalWebViewController.h index aa4d84c..074bde6 100644 --- a/SVWebViewController/SVModalWebViewController.h +++ b/SVWebViewController/SVModalWebViewController.h @@ -6,15 +6,14 @@ // // https://github.com/samvermette/SVWebViewController -#import +@import UIKit; -@class SVWebViewController; - -@interface SVModalWebViewController : UINavigationController +@interface SVModalWebViewController : UINavigationController - (id)initWithAddress:(NSString*)urlString; - (id)initWithURL:(NSURL *)URL; -@property (nonatomic, strong) UIColor *barsTintColor; +@property (nonatomic) UIColor *barTintColor; +@property (getter = isBarAttached, nonatomic) BOOL barAttached; @end diff --git a/SVWebViewController/SVModalWebViewController.m b/SVWebViewController/SVModalWebViewController.m index f801fa2..0324fb0 100644 --- a/SVWebViewController/SVModalWebViewController.m +++ b/SVWebViewController/SVModalWebViewController.m @@ -30,7 +30,7 @@ - (id)initWithURL:(NSURL *)URL { if (self = [super initWithRootViewController:self.webViewController]) { UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self.webViewController - action:@selector(doneButtonClicked:)]; + action:kDoneButtonClicked]; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) self.webViewController.navigationItem.leftBarButtonItem = doneButton; @@ -40,11 +40,28 @@ - (id)initWithURL:(NSURL *)URL { return self; } -- (void)viewWillAppear:(BOOL)animated { +- (void) viewWillAppear: (BOOL) animated { + [super viewWillAppear:NO]; self.webViewController.title = self.title; - self.navigationBar.tintColor = self.barsTintColor; -} + + if (self.barTintColor) { + + self.navigationBar.barTintColor = self.barTintColor; + } + +} // -viewWillAppear: + + +#pragma mark - UIToolbarDelegate methods. + + +- (UIBarPosition) positionForBar: (id) bar { + + return self.isBarAttached ? UIBarPositionTopAttached : UIBarPositionTop; + +} // -positionForBar: + @end diff --git a/SVWebViewController/SVWebViewController.h b/SVWebViewController/SVWebViewController.h index 42e9dfe..9749987 100644 --- a/SVWebViewController/SVWebViewController.h +++ b/SVWebViewController/SVWebViewController.h @@ -6,11 +6,33 @@ // // https://github.com/samvermette/SVWebViewController -#import "SVModalWebViewController.h" +@import UIKit; + +@protocol SVWebViewControllerDelegate; +@protocol SVWebViewPresenter +@end @interface SVWebViewController : UIViewController +@property (nonatomic) UIWebView *webView; +@property (weak, nonatomic) id delegate; + - (id)initWithAddress:(NSString*)urlString; - (id)initWithURL:(NSURL*)URL; +#define kDoneButtonClicked (@selector(doneButtonClicked:)) +- (void) doneButtonClicked: (id) sender; + +@end + +@protocol SVWebViewControllerDelegate + +@optional + +- (void) webViewControllerWillAppear: (SVWebViewController *) wvc; +- (void) webViewControllerDidAppear: (SVWebViewController *) wvc; + +- (void) webViewControllerWillDisappear: (SVWebViewController *) wvc; +- (void) webViewControllerDidDisappear: (SVWebViewController *) wvc; + @end diff --git a/SVWebViewController/SVWebViewController.m b/SVWebViewController/SVWebViewController.m index 2e08ebc..d4eb9ea 100644 --- a/SVWebViewController/SVWebViewController.m +++ b/SVWebViewController/SVWebViewController.m @@ -18,9 +18,10 @@ @interface SVWebViewController () @property (nonatomic, strong) UIBarButtonItem *stopBarButtonItem; @property (nonatomic, strong) UIBarButtonItem *actionBarButtonItem; -@property (nonatomic, strong) UIWebView *webView; @property (nonatomic, strong) NSURL *URL; +@property (nonatomic) NSUInteger webViewLoads; + - (id)initWithAddress:(NSString*)urlString; - (id)initWithURL:(NSURL*)URL; - (void)loadURL:(NSURL*)URL; @@ -41,9 +42,22 @@ @implementation SVWebViewController #pragma mark - Initialization - (void)dealloc { - [self.webView stopLoading]; - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - self.webView.delegate = nil; + + UIWebView *wv = self.webView; + + [wv stopLoading]; + + [NSOperationQueue.mainQueue addOperationWithBlock: ^{ + + [wv loadRequest: + [NSURLRequest requestWithURL: [NSURL URLWithString: @"about:blank"]]]; + }]; + if (!self.delegate) { + + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + } + wv.delegate = nil; + self.delegate = nil; } - (id)initWithAddress:(NSString *)urlString { @@ -65,33 +79,78 @@ - (void)loadURL:(NSURL *)pageURL { #pragma mark - View lifecycle -- (void)loadView { - self.view = self.webView; - [self loadURL:self.URL]; -} +- (void) loadView { + + UIView *view = [UIView.alloc initWithFrame: UIScreen.mainScreen.bounds]; + + view.backgroundColor = UIColor.blackColor; + + self.view = view; + +} // -loadView + +- (void) viewDidLoad { -- (void)viewDidLoad { [super viewDidLoad]; + [self updateToolbarItems]; -} -- (void)viewDidUnload { - [super viewDidUnload]; - self.webView = nil; - _backBarButtonItem = nil; - _forwardBarButtonItem = nil; - _refreshBarButtonItem = nil; - _stopBarButtonItem = nil; - _actionBarButtonItem = nil; -} +} // -viewDidLoad + + +//- (void)viewDidUnload { +// [super viewDidUnload]; +// self.webView = nil; +// _backBarButtonItem = nil; +// _forwardBarButtonItem = nil; +// _refreshBarButtonItem = nil; +// _stopBarButtonItem = nil; +// _actionBarButtonItem = nil; +//} + +- (void) viewWillAppear: (BOOL) animated { -- (void)viewWillAppear:(BOOL)animated { NSAssert(self.navigationController, @"SVWebViewController needs to be contained in a UINavigationController. If you are presenting SVWebViewController modally, use SVModalWebViewController instead."); [super viewWillAppear:animated]; if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { - [self.navigationController setToolbarHidden:NO animated:animated]; + [self.navigationController setToolbarHidden: NO animated: animated]; + } + self.navigationController.view.backgroundColor = UIColor.clearColor; + + UIWebView *wv = self.webView; + +// CGRect frame = self.view.bounds; +// CGFloat height = self.navigationController.navigationBar.bounds.size.height; +// +// frame.origin.y += height; +// frame.size.height -= height; +// + wv.frame = self.view.bounds; + + [self.view addSubview: wv]; + [self loadURL:self.URL]; + + wv.scrollView.backgroundColor = UIColor.clearColor; + + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webViewControllerWillAppear:)]) { + + [delegate webViewControllerWillAppear: self]; + } + +} // -viewWillAppear: + +- (void)viewDidAppear:(BOOL)animated { + [super viewDidAppear: animated]; + + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webViewControllerDidAppear:)]) { + + [delegate webViewControllerDidAppear: self]; } } @@ -101,11 +160,27 @@ - (void)viewWillDisappear:(BOOL)animated { if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) { [self.navigationController setToolbarHidden:YES animated:animated]; } + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webViewControllerWillDisappear:)]) { + + [delegate webViewControllerWillDisappear: self]; + } } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + + id delegate = self.delegate; + + if (!delegate) { + + [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + } + else if ([delegate respondsToSelector: @selector(webViewControllerDidDisappear:)]) { + + [delegate webViewControllerDidDisappear: self]; + } } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation { @@ -115,16 +190,21 @@ - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfa return toInterfaceOrientation != UIInterfaceOrientationPortraitUpsideDown; } + #pragma mark - Getters -- (UIWebView*)webView { + +- (UIWebView *) webView { + if(!_webView) { - _webView = [[UIWebView alloc] initWithFrame:[UIScreen mainScreen].bounds]; + _webView = [UIWebView.alloc initWithFrame: self.view.bounds]; _webView.delegate = self; _webView.scalesPageToFit = YES; } return _webView; -} + +} // -webView + - (UIBarButtonItem *)backBarButtonItem { if (!_backBarButtonItem) { @@ -171,18 +251,20 @@ - (UIBarButtonItem *)actionBarButtonItem { #pragma mark - Toolbar -- (void)updateToolbarItems { - self.backBarButtonItem.enabled = self.self.webView.canGoBack; - self.forwardBarButtonItem.enabled = self.self.webView.canGoForward; - self.actionBarButtonItem.enabled = !self.self.webView.isLoading; - - UIBarButtonItem *refreshStopBarButtonItem = self.self.webView.isLoading ? self.stopBarButtonItem : self.refreshBarButtonItem; - + +- (void) updateToolbarItems { + + self.backBarButtonItem.enabled = self.webView.canGoBack; + self.forwardBarButtonItem.enabled = self.webView.canGoForward; + self.actionBarButtonItem.enabled = !self.webViewLoads; + + UIBarButtonItem *refreshStopBarButtonItem = self.webViewLoads ? self.stopBarButtonItem : self.refreshBarButtonItem; + UIBarButtonItem *fixedSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFixedSpace target:nil action:nil]; UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { - CGFloat toolbarWidth = 250.0f; + fixedSpace.width = 35.0f; NSArray *items = [NSArray arrayWithObjects: @@ -195,15 +277,10 @@ - (void)updateToolbarItems { fixedSpace, self.actionBarButtonItem, nil]; - - UIToolbar *toolbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0.0f, 0.0f, toolbarWidth, 44.0f)]; - toolbar.items = items; - toolbar.barStyle = self.navigationController.navigationBar.barStyle; - toolbar.tintColor = self.navigationController.navigationBar.tintColor; self.navigationItem.rightBarButtonItems = items.reverseObjectEnumerator.allObjects; } - else { + NSArray *items = [NSArray arrayWithObjects: fixedSpace, self.backBarButtonItem, @@ -215,31 +292,69 @@ - (void)updateToolbarItems { self.actionBarButtonItem, fixedSpace, nil]; - - self.navigationController.toolbar.barStyle = self.navigationController.navigationBar.barStyle; - self.navigationController.toolbar.tintColor = self.navigationController.navigationBar.tintColor; +// self.navigationController.toolbar.barStyle = self.navigationController.navigationBar.barStyle; +// self.navigationController.toolbar.tintColor = self.navigationController.navigationBar.tintColor; self.toolbarItems = items; } -} + +} // -updateToolbarItems + #pragma mark - UIWebViewDelegate +- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { + + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webView:shouldStartLoadWithRequest:navigationType:)]) { + + return [delegate webView: webView shouldStartLoadWithRequest: request navigationType: navigationType]; + } + return YES; +} + - (void)webViewDidStartLoad:(UIWebView *)webView { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; + + self.webViewLoads++; [self updateToolbarItems]; -} + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webViewDidStartLoad:)]) { + + [delegate webViewDidStartLoad: webView]; + } + else { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES]; } +} - (void)webViewDidFinishLoad:(UIWebView *)webView { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; - + + self.webViewLoads = self.webViewLoads ? --self.webViewLoads : 0; self.navigationItem.title = [webView stringByEvaluatingJavaScriptFromString:@"document.title"]; + [self updateToolbarItems]; + + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webViewDidFinishLoad:)]) { + + [delegate webViewDidFinishLoad: webView]; + } + else { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; } } - (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { - [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; + + self.webViewLoads = self.webViewLoads ? --self.webViewLoads : 0; [self updateToolbarItems]; + + id delegate = self.delegate; + + if ([delegate respondsToSelector: @selector(webView:didFailLoadWithError:)]) { + + [delegate webView: webView didFailLoadWithError: error]; + } + else { [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO]; } } #pragma mark - Target actions @@ -253,23 +368,71 @@ - (void)goForwardClicked:(UIBarButtonItem *)sender { } - (void)reloadClicked:(UIBarButtonItem *)sender { + self.webViewLoads = 0; [self.webView reload]; + [self updateToolbarItems]; } - (void)stopClicked:(UIBarButtonItem *)sender { + self.webViewLoads = 0; [self.webView stopLoading]; - [self updateToolbarItems]; + [self updateToolbarItems]; } -- (void)actionButtonClicked:(id)sender { - NSArray *activities = @[[SVWebViewControllerActivitySafari new], [SVWebViewControllerActivityChrome new]]; +- (void) actionButtonClicked: (UIBarButtonItem *) sender { + + NSArray *activities = @[SVWebViewControllerActivitySafari.new, + SVWebViewControllerActivityChrome.new]; - UIActivityViewController *activityController = [[UIActivityViewController alloc] initWithActivityItems:@[self.self.webView.request.URL] applicationActivities:activities]; - [self presentViewController:activityController animated:YES completion:nil]; -} + UIActivityViewController *avc = nil; -- (void)doneButtonClicked:(id)sender { - [self dismissViewControllerAnimated:YES completion:NULL]; -} + avc = [UIActivityViewController.alloc + initWithActivityItems: @[self.webView.request.URL] + applicationActivities:activities]; + + if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) { + + UIPopoverController *pc = nil; + + pc = [UIPopoverController.alloc initWithContentViewController: avc]; + + pc.popoverContentSize = avc.preferredContentSize; +#if (__IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_8_0) + avc.completionWithItemsHandler = ^(NSString *activityType, BOOL completed, NSArray *returnedItems, NSError *activityError) { + + [pc dismissPopoverAnimated: YES]; + }; +#else + avc.completionHandler = ^(NSString *activityType, BOOL completed) { + + [pc dismissPopoverAnimated: YES]; + }; +#endif + [pc presentPopoverFromBarButtonItem: sender + permittedArrowDirections: UIPopoverArrowDirectionAny + animated: YES]; + } + else { + + [self.navigationController presentViewController: avc + animated: YES + completion: NULL]; + } + +} // -actionButtonClicked: + + +- (void) doneButtonClicked: (id) sender { + + [self.webView loadRequest: + [NSURLRequest requestWithURL: + [NSURL URLWithString: @"about:blank"]]]; + + dispatch_async(dispatch_get_main_queue(), ^{ + + [self dismissViewControllerAnimated:YES completion:NULL]; + }); + +} // -doneButtonClicked: @end diff --git a/SVWebViewController/UIActivities/Chrome/SVWebViewControllerActivityChrome.m b/SVWebViewController/UIActivities/Chrome/SVWebViewControllerActivityChrome.m index f50f68e..dab6389 100644 --- a/SVWebViewController/UIActivities/Chrome/SVWebViewControllerActivityChrome.m +++ b/SVWebViewController/UIActivities/Chrome/SVWebViewControllerActivityChrome.m @@ -7,32 +7,43 @@ // https://github.com/samvermette/SVWebViewController #import "SVWebViewControllerActivityChrome.h" +#import "OpenInChromeController.h" @implementation SVWebViewControllerActivityChrome -- (NSString *)schemePrefix { - return @"googlechrome://"; -} - - (NSString *)activityTitle { return NSLocalizedStringFromTable(@"Open in Chrome", @"SVWebViewController", nil); } -- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { - for (id activityItem in activityItems) { - if ([activityItem isKindOfClass:[NSURL class]] && [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:self.schemePrefix]]) { - return YES; - } - } +- (BOOL) canPerformWithActivityItems: (NSArray *) activityItems { + + if ([[OpenInChromeController sharedInstance] isChromeInstalled]) { + + BOOL canPerform = NO; + + for (NSURL *url in activityItems) { + + if ([url isKindOfClass:[NSURL class]]) { + + NSString *scheme = url.scheme; + + canPerform |= ([scheme isEqualToString: @"http"] || + [scheme isEqualToString: @"https"]); + } + } + return canPerform; + } return NO; -} -- (void)performActivity { - NSString *openingURL = [self.URLToOpen.absoluteString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; - NSURL *activityURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", self.schemePrefix, openingURL]]; - [[UIApplication sharedApplication] openURL:activityURL]; - - [self activityDidFinish:YES]; -} +} // -canPerformWithActivityItems: + + +- (void) performActivity { + + [[OpenInChromeController sharedInstance] openInChrome: self.URLToOpen]; + + [self activityDidFinish: YES]; + +} // -performActivity @end diff --git a/SVWebViewController/UIActivities/SVWebViewControllerActivity.h b/SVWebViewController/UIActivities/SVWebViewControllerActivity.h index 1d643e8..ad3fa10 100644 --- a/SVWebViewController/UIActivities/SVWebViewControllerActivity.h +++ b/SVWebViewController/UIActivities/SVWebViewControllerActivity.h @@ -6,7 +6,8 @@ // // -#import +@import UIKit; +NS_ASSUME_NONNULL_BEGIN @interface SVWebViewControllerActivity : UIActivity @@ -14,3 +15,4 @@ @property (nonatomic, strong) NSString *schemePrefix; @end +NS_ASSUME_NONNULL_END diff --git a/SVWebViewController/UIActivities/SVWebViewControllerActivity.m b/SVWebViewController/UIActivities/SVWebViewControllerActivity.m index df362b6..943480b 100644 --- a/SVWebViewController/UIActivities/SVWebViewControllerActivity.m +++ b/SVWebViewController/UIActivities/SVWebViewControllerActivity.m @@ -8,6 +8,8 @@ #import "SVWebViewControllerActivity.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wnullable-to-nonnull-conversion" @implementation SVWebViewControllerActivity - (NSString *)activityType { @@ -30,3 +32,4 @@ - (void)prepareWithActivityItems:(NSArray *)activityItems { } @end +#pragma clang diagnostic pop diff --git a/SVWebViewController/UIActivities/Safari/SVWebViewControllerActivitySafari.m b/SVWebViewController/UIActivities/Safari/SVWebViewControllerActivitySafari.m index 5235684..afef810 100644 --- a/SVWebViewController/UIActivities/Safari/SVWebViewControllerActivitySafari.m +++ b/SVWebViewController/UIActivities/Safari/SVWebViewControllerActivitySafari.m @@ -15,14 +15,25 @@ - (NSString *)activityTitle { return NSLocalizedStringFromTable(@"Open in Safari", @"SVWebViewController", nil); } -- (BOOL)canPerformWithActivityItems:(NSArray *)activityItems { - for (id activityItem in activityItems) { - if ([activityItem isKindOfClass:[NSURL class]] && [[UIApplication sharedApplication] canOpenURL:activityItem]) { - return YES; - } - } - return NO; -} +- (BOOL) canPerformWithActivityItems: (NSArray *) activityItems { + + BOOL canPerform = NO; + + for (NSURL *url in activityItems) { + + if ([url isKindOfClass:[NSURL class]]) { + + NSString *scheme = url.scheme; + + canPerform |= (([scheme isEqualToString: @"http"] || + [scheme isEqualToString: @"https"]) && + [[UIApplication sharedApplication] canOpenURL: url]); + } + } + return canPerform; + +} // -canPerformWithActivityItems: + - (void)performActivity { BOOL completed = [[UIApplication sharedApplication] openURL:self.URLToOpen]; diff --git a/SVWebViewController/vendors/OpenInChromeController b/SVWebViewController/vendors/OpenInChromeController new file mode 160000 index 0000000..ca39b6a --- /dev/null +++ b/SVWebViewController/vendors/OpenInChromeController @@ -0,0 +1 @@ +Subproject commit ca39b6a6d6f6e646a206cc07ca7d92c977306afc