Files
shadowsocks-iOS/ShadowWeb/SWBViewController.m
2014-02-27 16:47:18 +08:00

632 lines
22 KiB
Objective-C

//
// SWBViewController.m
// ShadowWeb
//
// Created by clowwindy on 2/16/13.
// Copyright (c) 2013 clowwindy. All rights reserved.
//
#import <AVFoundation/AVFoundation.h>
#import "QRCodeViewController.h"
#import "SWBViewController.h"
#import "ShadowsocksRunner.h"
#import "ProxySettingsTableViewController.h"
#import "SWBAboutController.h"
#define kNewTabAddress @"shadowweb:newtab"
#define kAboutBlank @"shadowweb:blank"
@interface SWBViewController () {
AVAudioPlayer *player;
UIPopoverController *settingsPC;
UIBarButtonItem *actionBarButton;
}
@end
@implementation SWBViewController
#pragma mark - View lifecycle
- (UIStatusBarStyle)preferredStatusBarStyle {
return UIStatusBarStyleDefault;
}
- (UIRectEdge) edgesForExtendedLayout {
return UIRectEdgeNone;
}
- (CGFloat) statusBarHeight {
return ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) ?
20 : 0;
}
- (void)viewDidLoad {
[super viewDidLoad];
// If don't do this, you'll see some white edge when doing the rotation
self.view.clipsToBounds = YES;
self.view.backgroundColor = [UIColor whiteColor];
currentTabTag = 0;
CGRect bounds = self.view.bounds;
self.tabBar = [[SWBTabBarView alloc] initWithFrame:CGRectMake(0, bounds.size.height - kTabBarHeight, bounds.size.width, kTabBarHeight)];
self.webViewContainer = [[SWBWebViewContainer alloc] initWithFrame:CGRectMake(0, 0, bounds.size.width, bounds.size.height - kTabBarHeight)];
// _webViewContainer.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
_webViewContainer.delegate = self;
self.tabBar.delegate = self;
self.webViewContainer.delegate = self;
[self initPageManager];
[self initPagesAndTabs];
// init address bar
self.addrbar = [[UIToolbar alloc] initWithFrame:CGRectMake(0, [self statusBarHeight], bounds.size.width, kToolBarHeight)];
// init bar buttons
CGRect urlFieldFrame = CGRectInset(_addrbar.bounds, 12 + kActionButtonWidth * 0.5f, 7);
urlFieldFrame = CGRectOffset(urlFieldFrame, -kActionButtonWidth * 0.5f, 0);
self.urlField = [[UITextField alloc] initWithFrame:urlFieldFrame];
[_urlField setBorderStyle:UITextBorderStyleRoundedRect];
[_urlField setKeyboardType:UIKeyboardTypeURL];
UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithCustomView:_urlField];
[item setStyle:UIBarButtonItemStylePlain];
[_urlField setReturnKeyType:UIReturnKeyGo];
[_urlField setDelegate:self];
[_urlField addTarget:self action:@selector(textFieldDidEndEditing) forControlEvents:UIControlEventEditingDidEndOnExit];
[_urlField setContentVerticalAlignment:UIControlContentVerticalAlignmentCenter];
[_urlField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
[_urlField setAutocorrectionType:UITextAutocorrectionTypeNo];
[_urlField setClearButtonMode:UITextFieldViewModeWhileEditing];
[_urlField setPlaceholder:@"URL"];
[_urlField setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
UIBarButtonItem *_cancelButton = [[UIBarButtonItem alloc] initWithTitle:_L(Cancel) style:UIBarButtonItemStyleBordered target:self action:@selector(cancel)];
_cancelButton.width = kCancelButtonWidth;
UIBarButtonItem *_actionButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemAction target:self action:@selector(addrBarViewMoreDidClick)];
_actionButton.width = kActionButtonWidth;
actionBarButton = _actionButton;
self.addrItemsInactive = [NSMutableArray arrayWithObjects:
[[UIBarButtonItem alloc] initWithCustomView:_urlField],
[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil],
_actionButton,
nil];
self.addrItemsActive = [NSMutableArray arrayWithObjects:
[self.addrItemsInactive objectAtIndex:0],
_cancelButton,
nil];
[_addrbar setItems:_addrItemsInactive];
// [_addrbar setBarStyle:UIBarStyleBlack];
if ([_addrbar respondsToSelector:@selector(setBarTintColor:)]) {
[_addrbar setBarTintColor:[UIColor whiteColor]];
}
// add subviews
[self.view addSubview:_webViewContainer];
[self.view addSubview:_addrbar];
[self.view addSubview:_tabBar];
[self relayout:bounds];
// Keyboard hide notification
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(keyboardHiden:)
name:UIKeyboardWillHideNotification
object:nil];
// ActionSheet
[self initActionSheet];
// [self play];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
[_webViewContainer releaseBackgroundWebViews];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
[self scrollViewDidScroll:[self currentWebView].scrollView];
}
- (void)viewWillLayoutSubviews {
[self relayout:self.view.bounds];
}
- (void)relayout:(CGRect)bounds {
CGRect addrBarRect = CGRectMake(0, _addrbar.frame.origin.y, bounds.size.width, kToolBarHeight);
CGRect webViewContainerRect = CGRectMake(0, [self statusBarHeight], bounds.size.width, bounds.size.height - kTabBarHeight - [self statusBarHeight]);
CGRect tabBarRect = CGRectMake(0, bounds.size.height - kTabBarHeight, bounds.size.width, kTabBarHeight);
_addrbar.frame = addrBarRect;
_webViewContainer.frame = webViewContainerRect;
_tabBar.frame = tabBarRect;
}
- (void)viewDidAppear:(BOOL)animated {
if ([ShadowsocksRunner settingsAreNotComplete]) {
[self showSettings];
}
}
#pragma mark - webview
- (void)updateWebViewTitle:(UIWebView *)webView {
NSString *title = [_webViewContainer titleForWebView:(SWBWebView *) webView];
SWBPage *page = [_pageManager pageByTag:webView.tag];
if (title) {
page.title = title;
// [visitRecordManager setTitleForURL:[(AQWebView *)webView aqLocationHref] title:title];
}
if (title == nil || [title isEqualToString:@""]) {
if (webView.loading) {
title = NSLocalizedString(@"Loading", "Loading");
} else {
title = NSLocalizedString(@"Untitled", "Untitled");
}
}
[_tabBar setTitleForTab:webView.tag title:title];
}
- (void)openURL:(NSString *)urlString {
NSURL *url = [NSURL URLWithString:urlString];
if (!url || [urlString rangeOfString:@":"].length == 0) {
urlString = [@"http://" stringByAppendingString:urlString];
url = [NSURL URLWithString:urlString];
}
if (url) {
NSURLRequest *request = [NSURLRequest requestWithURL:url];
if (request) {
[_webViewContainer.currentSWBWebView loadRequest:request];
}
} else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil message:_L(incorrect
URL) delegate:nil cancelButtonTitle:_L(OK) otherButtonTitles:nil];
[alert show];
}
}
- (SWBWebView *)currentWebView {
return [_webViewContainer currentSWBWebView];
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
}
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
BOOL result = YES;
#ifdef DEBUG
// NSLog(@"shouldStartLoadWithRequest tag:%d navtype:%d %@", webView.tag, navigationType, [request URL]);
#endif
// NSString *scheme = [[request URL] scheme];
if ([[[request URL] absoluteString] caseInsensitiveCompare:kNewTabAddress] == NSOrderedSame) {
// [self openLinkInNewTab:[(SWBWebView *)webView lastClickedLink]];
}
else {
if (navigationType == UIWebViewNavigationTypeLinkClicked ||
navigationType == UIWebViewNavigationTypeBackForward) {
SWBPage *page = [_pageManager pageByTag:webView.tag];
NSString *url = [[request URL] absoluteString];
page.url = url;
}
}
return result;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
[self resetTabBarButtonsStatus];
[self updateWebViewTitle:webView];
[_tabBar setLoadingForTab:webView.tag loading:NO];
if ([[[[webView request] URL] absoluteString] caseInsensitiveCompare:[(SWBWebView *) webView locationHref]] == NSOrderedSame) {
NSString *url = [[[webView request] URL] absoluteString];
NSString *title = [((SWBWebView *) webView) pageTitle];
_urlField.text = url;
SWBPage *page = [_pageManager pageByTag:webView.tag];
page.url = url;
page.title = title;
}
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
[_tabBar setLoadingForTab:webView.tag loading:YES];
}
#pragma mark - WebView Scrolling
- (void)initWebViewScrolling:(SWBWebView *)webView {
UIScrollView *scrollView = webView.scrollView;
scrollView.delegate = self;
[scrollView setContentInset:UIEdgeInsetsMake(kToolBarHeight, 0, 0, 0)];
[scrollView setScrollIndicatorInsets:UIEdgeInsetsMake(kToolBarHeight, 0, 0, 0)];
[scrollView scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:NO];
[self scrollViewDidScroll:scrollView];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if ([self currentWebView].scrollView == scrollView) {
if (scrollView.contentOffset.y < 0) {
[scrollView setScrollIndicatorInsets:UIEdgeInsetsMake(-scrollView.contentOffset.y, 0, 0, 0)];
} else {
[scrollView setScrollIndicatorInsets:UIEdgeInsetsMake(0, 0, 0, 0)];
}
_addrbar.frame = CGRectMake(0, [self statusBarHeight] - kToolBarHeight - scrollView.contentOffset.y, _addrbar.frame.size.width, kToolBarHeight);
CGFloat offset = MIN(kToolBarHeight, MAX(0, (kToolBarHeight + scrollView.contentOffset.y)));
CGFloat opacity = offset / kToolBarHeight;
_urlField.alpha = (1 - opacity)*(1 - opacity);
// NSLog(@"offset: %f, contentInset top: %f", offset, scrollView.contentInset.top);
[scrollView setContentInset:UIEdgeInsetsMake(kToolBarHeight - offset, 0, 0, 0)];
}
}
#pragma mark - ActionSheet
- (void)initActionSheet {
self.actionSheet = [[UIActionSheet alloc] initWithTitle:nil delegate:self cancelButtonTitle:_L(Cancel) destructiveButtonTitle:nil otherButtonTitles:_L(New
Tab), _L(Back), _L(Forward), _L(Reload), _L(Settings), _L(Config via QRCode), _L(Help), _L(About), nil];
[_actionSheet setActionSheetStyle:UIActionSheetStyleBlackTranslucent];
}
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex {
QRCodeViewController *qrCodeViewController = [[QRCodeViewController alloc] initWithReturnBlock:^(NSString *code) {
if (code) {
NSURL *URL = [NSURL URLWithString:code];
if (URL) {
[[UIApplication sharedApplication] openURL:URL];
}
}
}];
switch (buttonIndex) {
case 0:
[self openLinkInNewTab:kNewTabAddress];
_urlField.text = @"";
[NSTimer scheduledTimerWithTimeInterval:0.20 target:_urlField selector:@selector(becomeFirstResponder) userInfo:nil repeats:NO];
break;
case 1:
[[self currentWebView] goBack];
break;
case 2:
[[self currentWebView] goForward];
break;
case 3:
[[self currentWebView] reload];
break;
case 4:
[self showSettings];
break;
case 5:
[self presentModalViewController:qrCodeViewController animated:YES];
break;
case 6:
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"https://github.com/shadowsocks/shadowsocks-iOS/wiki/Help"]];
break;
case 7:
[self showAbout];
break;
default:
break;
}
}
- (void)showAbout {
SWBAboutController *settingsController = [[SWBAboutController alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:settingsController];
// nav.navigationBar.tintColor = [UIColor blackColor];
// nav.navigationBar.barStyle = UIBarStyleBlackOpaque;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
settingsPC = [[UIPopoverController alloc] initWithContentViewController:nav];
settingsController.myPopoverController = settingsPC;
CGRect newTabRect = [self.tabBar aNewTabButton].frame;
newTabRect.size.width = newTabRect.size.height;
CGRect rect = [self.tabBar convertRect:newTabRect toView:self.view];
// [settingsPC presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[settingsPC presentPopoverFromBarButtonItem:actionBarButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentModalViewController:nav animated:YES];
}
}
- (void)showSettings {
ProxySettingsTableViewController *settingsController = [[ProxySettingsTableViewController alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:settingsController];
// nav.navigationBar.tintColor = [UIColor blackColor];
// nav.navigationBar.barStyle = UIBarStyleBlackOpaque;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
settingsPC = [[UIPopoverController alloc] initWithContentViewController:nav];
settingsController.myPopoverController = settingsPC;
CGRect newTabRect = [self.tabBar aNewTabButton].frame;
newTabRect.size.width = newTabRect.size.height;
CGRect rect = [self.tabBar convertRect:newTabRect toView:self.view];
// [settingsPC presentPopoverFromRect:rect inView:self.view permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
[settingsPC presentPopoverFromBarButtonItem:actionBarButton permittedArrowDirections:UIPopoverArrowDirectionAny animated:YES];
} else {
[self presentModalViewController:nav animated:YES];
}
}
#pragma mark - TabBar
- (void)resetTabBarButtonsStatus {
// SWBWebView *currentWebView = [self currentWebView];
// backButton.enabled = currentWebView.canGoBack;
// forwardButton.enabled = currentWebView.canGoForward;
// stopButton.enabled = currentWebView.loading;
// @try {
// NSString *urlString = [[self currentWebView] aqLocationHref];
// NSURL *url = [NSURL URLWithString:urlString];
// if (AQ_is_nonlocal_http([url scheme])) {
// actionButton.enabled = YES;
// // refreshButton.enabled = YES;
// } else {
// actionButton.enabled = NO;
// // refreshButton.enabled = NO;
// }
// }
// @catch (NSException *exception) {
// }
// @finally {
// }
}
- (void)tabBarViewNewTabButtonDidClick {
[self openLinkInNewTab:kNewTabAddress];
_urlField.text = @"";
[NSTimer scheduledTimerWithTimeInterval:0.20 target:_urlField selector:@selector(becomeFirstResponder) userInfo:nil repeats:NO];
}
- (void)addrBarViewMoreDidClick {
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
CGRect newTabRect = [self.tabBar aNewTabButton].frame;
newTabRect.size.width = newTabRect.size.height;
CGRect rect = [self.tabBar convertRect:newTabRect toView:self.view];
// [self.actionSheet showFromRect:rect inView:self.view animated:YES];
[self.actionSheet showFromBarButtonItem:actionBarButton animated:YES];
} else {
[self.actionSheet showInView:self.view];
}
}
- (void)tabBarViewTabDidClose:(SWBTab *)tab {
// NSString *title = [[_webViewContainer webViewByTag:tab.tag] pageTitle];
// NSString *urlString =[[_pageManager pageByTag:tab.tag] url];
// if (urlString) {
// NSURL *url = [[NSURL alloc] initWithString:urlString];
// if (AQ_is_nonlocal_http([url scheme])) {
// [visitRecordManager closeAURL:urlString withTitle:title];
// }
// [url release];
// }
[_pageManager removePage:tab.tag];
[_webViewContainer closeWebView:tab.tag];
if (_tabBar.currentTab) {
[_webViewContainer switchToWebView:_tabBar.currentTab.tag];
}
if ([[_pageManager pages] count] == 0) {
// [self tabBarViewNewTabButtonDidClick];
[self openLinkInNewTab:@"http://www.twitter.com/"];
[NSTimer scheduledTimerWithTimeInterval:0.20 target:_urlField selector:@selector(becomeFirstResponder) userInfo:nil repeats:NO];
}
}
- (void)tabBarViewTabDidMove:(SWBTab *)tab toIndex:(NSInteger)index {
// [pageManager reorderPage:tabBar.tabs];
// 目前没有必要
}
- (void)tabBarViewTabDidSelect:(SWBTab *)tab {
[_webViewContainer switchToWebView:tab.tag];
}
#pragma mark - page manager
- (void)initPageManager {
lastTag = 0;
self.pageManager = [[SWBPageManager alloc] init];
[_pageManager load];
}
- (NSInteger)genTag {
return lastTag++;
}
- (void)initPagesAndTabs {
[_pageManager initMappingAndTabsByPages];
NSArray *pages = _pageManager.pages;
// NSInteger currentTabTag = 0;
NSUInteger count = [pages count];
for (int i = 0; i < count; i++) {
if ([[[pages objectAtIndex:i] selected] boolValue]) {
currentTabTag = i;
}
}
for (int i = 0; i < count; i++) {
[self addNewTab];
}
if ([pages count] == 0) {
// [self tabBarViewNewTabButtonDidClick];
[self openLinkInNewTab:@"http://www.google.com/"];
[NSTimer scheduledTimerWithTimeInterval:0.20 target:_urlField selector:@selector(becomeFirstResponder) userInfo:nil repeats:NO];
} else {
[_tabBar setCurrentTabWithTag:currentTabTag];
}
}
- (void)savePageIndex {
// save page index order
// NSArray *tabs = [tabBar tabs];
// for (int i = 0; i < [tabs count]; i++) {
// [[pageManager pageByTag:[[tabs objectAtIndex:i] tag]] setIndex:[NSNumber numberWithInt:i]];
// }
}
- (void)addNewEmptyTab {
NSInteger newTag = [self genTag];
[_webViewContainer newWebView:newTag];
}
- (void)addNewTab {
SWBTab *newTab = [_tabBar newTab];
[_webViewContainer newWebView:newTab.tag];
_tabBar.currentTab = newTab;
}
- (void)openLinkInNewTab:(NSString *)urlString {
SWBTab *newTab = [_tabBar newTab];
SWBPage *page = [_pageManager addPageWithTag:newTab.tag];
page.url = urlString;
page.title = @"";
[_webViewContainer newWebView:newTab.tag];
_tabBar.currentTab = newTab;
}
- (void)saveData {
[_pageManager save];
}
#pragma mark - WebViewContainer
- (void)syncPageManagerSelectionStatusWithSelectedTag:(NSInteger)tag {
NSNumber *yes = [NSNumber numberWithBool:YES];
NSNumber *no = [NSNumber numberWithBool:NO];
for (SWBPage *page in _pageManager.pages) {
page.selected = no;
}
[_pageManager pageByTag:tag].selected = yes;
}
- (void)webViewContainerWebViewDidCreateNew:(SWBWebView *)webView {
SWBPage *page = [_pageManager pageByTag:webView.tag];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:page.url]];
[webView loadRequest:request];
[self initWebViewScrolling:webView];
[self resetTabBarButtonsStatus];
[self syncPageManagerSelectionStatusWithSelectedTag:webView.tag];
}
- (void)webViewContainerWebViewDidSwitchToWebView:(SWBWebView *)webView {
[self resetTabBarButtonsStatus];
[self syncPageManagerSelectionStatusWithSelectedTag:webView.tag];
_urlField.text = webView.locationHref;
[self scrollViewDidScroll:webView.scrollView];
}
- (void)webViewContainerWebViewNeedToReload:(SWBWebView *)webView tag:(NSInteger)tag {
SWBPage *page = [_pageManager pageByTag:tag];
NSURL *url = [NSURL URLWithString:page.url];
if (url != nil) {
NSURLRequest *request = [NSURLRequest requestWithURL:url];
[webView loadRequest:request];
[self resetTabBarButtonsStatus];
}
}
#pragma mark - Text Field
- (void)hideKeyboard {
[_urlField resignFirstResponder];
[self hideCancelButton];
}
- (void)hideCancelButton {
[_addrbar setItems:_addrItemsInactive animated:YES];
[UIView beginAnimations:nil context:NULL];
CGRect bounds = [_addrbar bounds];
bounds = CGRectInset(bounds, 12 + kActionButtonWidth * 0.5f, 7);
bounds = CGRectOffset(bounds, -kActionButtonWidth * 0.5f, 0);
[_urlField setFrame:bounds];
[UIView commitAnimations];
}
- (void)cancel {
[self hideKeyboard];
}
- (void)textFieldDidBeginEditing:(UITextField *)textField {
[_addrbar setItems:_addrItemsActive animated:YES];
[UIView beginAnimations:nil context:NULL];
CGRect bounds = [_addrbar bounds];
bounds = CGRectInset(bounds, 12 + kCancelButtonWidth * 0.5f, 7);
bounds = CGRectOffset(bounds, -kCancelButtonWidth * 0.5f, 0);
[_urlField setFrame:bounds];
[UIView commitAnimations];
}
- (void)textFieldDidEndEditing {
[self hideKeyboard];
[self openURL:_urlField.text];
}
- (BOOL)textFieldShouldEndEditing:(UITextField *)textField {
return YES;
}
- (void)keyboardHiden:(NSNotification *)notification {
// [self hideCancelButton];
}
#pragma mark audio
- (BOOL)canBecomeFirstResponder {
return YES;
}
- (void)play {
// Play music, so app can run in the backgound.
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];
NSURL *url = [[NSBundle mainBundle] URLForResource:@"silence" withExtension:@"wav"];
player = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:nil];
[player prepareToPlay];
[player setVolume:0];
player.numberOfLoops = -1;
[player play];
[self becomeFirstResponder];
}
- (void)remoteControlReceivedWithEvent:(UIEvent *)event {
switch (event.subtype) {
case UIEventSubtypeRemoteControlPlay:
[player play];
break;
case UIEventSubtypeRemoteControlPause:
[player pause];
break;
default:
break;
}
}
@end