Skip to content
This repository has been archived by the owner on Jan 13, 2022. It is now read-only.

Commit

Permalink
[UI] iPad support with UISplitViewController.
Browse files Browse the repository at this point in the history
  • Loading branch information
jverkoey committed Nov 17, 2010
1 parent 7499b4a commit aa52d07
Show file tree
Hide file tree
Showing 27 changed files with 546 additions and 33 deletions.
5 changes: 5 additions & 0 deletions src/Three20UI/Headers/TTNavigator.h
Expand Up @@ -21,6 +21,11 @@
*/
UIViewController* TTOpenURL(NSString* URL);

/**
* Shortcut for calling [[TTBaseNavigator navigatorForView:view] openURL:]
*/
UIViewController* TTOpenURLFromView(NSString* URL, UIView* view);

/**
* A URL-based navigation system with built-in persistence.
* Add support for model-based controllers and implement the legacy global instance accessor.
Expand Down
49 changes: 49 additions & 0 deletions src/Three20UI/Headers/TTSplitViewController.h
@@ -0,0 +1,49 @@
//
// Copyright 2009-2010 Facebook
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "Three20UINavigator/TTNavigatorRootContainer.h"

@class TTNavigator;

/**
* A split view controller that implements the navigator root protocol.
*
* See the TTCatalog sample app for an example of this controller in action.
*/
@interface TTSplitViewController : UISplitViewController <
UISplitViewControllerDelegate,
TTNavigatorRootContainer
> {
@private
TTNavigator* _leftNavigator;
TTNavigator* _rightNavigator;

UIBarButtonItem* _splitViewButton;
UIPopoverController* _popoverSplitController;
}

@property (nonatomic, readonly) TTNavigator* leftNavigator;
@property (nonatomic, readonly) TTNavigator* rightNavigator;
@property (nonatomic, retain) UIBarButtonItem* splitViewButton;
@property (nonatomic, retain) UIPopoverController* popoverSplitController;


/**
* Show/hide the button as the right-side navigator's root navigation item's left button.
*/
- (void)updateSplitViewButton;

@end
1 change: 1 addition & 0 deletions src/Three20UI/Headers/Three20UI.h
Expand Up @@ -17,6 +17,7 @@
// UI Controllers
#import "Three20UI/TTNavigator.h"
#import "Three20UI/TTViewController.h"
#import "Three20UI/TTSplitViewController.h"
#import "Three20UI/TTNavigationController.h"
#import "Three20UI/TTExtensionsController.h"
#import "Three20UI/TTWebController.h"
Expand Down
5 changes: 0 additions & 5 deletions src/Three20UI/Headers/UIViewAdditions.h
Expand Up @@ -172,9 +172,4 @@
*/
- (void)dismissAsKeyboard:(BOOL)animated;

/**
* The view controller whose view contains this view.
*/
- (UIViewController*)viewController;

@end
2 changes: 1 addition & 1 deletion src/Three20UI/Sources/TTLink.m
Expand Up @@ -69,7 +69,7 @@ - (void)dealloc {

///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)linkTouched {
[[TTNavigator navigator] openURLAction:_URLAction];
[[TTBaseNavigator navigatorForView:self] openURLAction:_URLAction];
}


Expand Down
8 changes: 8 additions & 0 deletions src/Three20UI/Sources/TTNavigator.m
Expand Up @@ -47,6 +47,14 @@
}


///////////////////////////////////////////////////////////////////////////////////////////////////
UIViewController* TTOpenURLFromView(NSString* URL, UIView* view) {
return [[TTBaseNavigator navigatorForView:view] openURLAction:
[[TTURLAction actionWithURLPath:URL]
applyAnimated:YES]];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
Expand Down
7 changes: 4 additions & 3 deletions src/Three20UI/Sources/TTPhotoViewController.m
Expand Up @@ -362,8 +362,9 @@ - (void)showThumbnails {
if (URL) {
// The photo source has a URL mapping in TTURLMap, so we use that to show the thumbs
NSDictionary* query = [NSDictionary dictionaryWithObject:self forKey:@"delegate"];
_thumbsController = [[[TTNavigator navigator] viewControllerForURL:URL query:query] retain];
[[TTNavigator navigator].URLMap setObject:_thumbsController forURL:URL];
TTBaseNavigator* navigator = [TTBaseNavigator navigatorForView:self.view];
_thumbsController = [[navigator viewControllerForURL:URL query:query] retain];
[navigator.URLMap setObject:_thumbsController forURL:URL];
} else {
// The photo source had no URL mapping in TTURLMap, so we let the subclass show the thumbs
_thumbsController = [[self createThumbsViewController] retain];
Expand All @@ -372,7 +373,7 @@ - (void)showThumbnails {
}

if (URL) {
TTOpenURL(URL);
TTOpenURLFromView(URL, self.view);
} else {
if ([self.navigationController isKindOfClass:[TTNavigationController class]]) {
[(TTNavigationController*)self.navigationController
Expand Down
190 changes: 190 additions & 0 deletions src/Three20UI/Sources/TTSplitViewController.m
@@ -0,0 +1,190 @@
//
// Copyright 2009-2010 Facebook
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#import "Three20UI/TTSplitViewController.h"

// UI
#import "Three20UI/TTNavigator.h"

// Core
#import "Three20Core/TTCorePreprocessorMacros.h"
#import "Three20Core/TTDebug.h"


///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
@implementation TTSplitViewController

@synthesize leftNavigator = _leftNavigator;
@synthesize rightNavigator = _rightNavigator;
@synthesize splitViewButton = _splitViewButton;
@synthesize popoverSplitController = _popoverSplitController;


///////////////////////////////////////////////////////////////////////////////////////////////////
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {
self.delegate = self;

self.viewControllers = [NSArray arrayWithObjects:
[[[UINavigationController alloc] initWithNibName: nil
bundle: nil] autorelease],
[[[UINavigationController alloc] initWithNibName: nil
bundle: nil] autorelease],
nil];

_leftNavigator = [[TTNavigator alloc] init];
_leftNavigator.rootContainer = self;

_rightNavigator = [[TTNavigator alloc] init];
_rightNavigator.rootContainer = self;
}

return self;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)dealloc {
self.delegate = nil;
TT_RELEASE_SAFELY(_leftNavigator);
TT_RELEASE_SAFELY(_rightNavigator);
TT_RELEASE_SAFELY(_splitViewButton);
TT_RELEASE_SAFELY(_popoverSplitController);

[super dealloc];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)updateSplitViewButton {
if (nil != _rightNavigator.rootViewController) {

if (nil != _leftNavigator.rootViewController) {
UINavigationController* navController =
(UINavigationController*)_leftNavigator.rootViewController;
UIViewController* topViewController = navController.topViewController;
if (nil != topViewController) {
self.splitViewButton.title = topViewController.title;
}
}

if (nil == self.splitViewButton.title) {
self.splitViewButton.title = @"Default Title";
}

UINavigationController* navController =
(UINavigationController*)_rightNavigator.rootViewController;
UIViewController* topViewController = navController.topViewController;
UINavigationItem* navItem = topViewController.navigationItem;

navItem.leftBarButtonItem = _splitViewButton;
}
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];

[self updateSplitViewButton];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark TTNavigatorRootContainer


///////////////////////////////////////////////////////////////////////////////////////////////////
- (TTBaseNavigator*)getNavigatorForController:(UIViewController*)controller {
if (controller == [self.viewControllers objectAtIndex:0]) {
return _leftNavigator;

} else if (controller == [self.viewControllers objectAtIndex:1]) {
return _rightNavigator;
}

return nil;
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)navigator:(TTBaseNavigator*)navigator setRootViewController:(UIViewController*)controller {
if (_rightNavigator == navigator) {
self.viewControllers = [NSArray arrayWithObjects:
[self.viewControllers objectAtIndex:0],
controller,
nil];

[self updateSplitViewButton];

} else if (_leftNavigator == navigator) {
self.viewControllers = [NSArray arrayWithObjects:
controller,
[self.viewControllers objectAtIndex:1],
nil];

[self updateSplitViewButton];

} else {
// Invalid navigator sent here.
TTDASSERT(NO);
}
}


///////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
#pragma mark UISplitViewControllerDelegate


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)splitViewController: (UISplitViewController*)svc
willHideViewController: (UIViewController *)aViewController
withBarButtonItem: (UIBarButtonItem*)barButtonItem
forPopoverController: (UIPopoverController*)pc {
self.splitViewButton = barButtonItem;

[self updateSplitViewButton];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)splitViewController: (UISplitViewController*)svc
willShowViewController: (UIViewController *)aViewController
invalidatingBarButtonItem: (UIBarButtonItem *)barButtonItem {
self.splitViewButton = nil;

[self updateSplitViewButton];
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)splitViewController: (UISplitViewController*)svc
popoverController: (UIPopoverController*)pc
willPresentViewController: (UIViewController *)aViewController {
self.popoverSplitController = pc;

pc.contentViewController = aViewController;
}


@end

4 changes: 2 additions & 2 deletions src/Three20UI/Sources/TTTableView.m
Expand Up @@ -116,10 +116,10 @@ - (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event {
// the node implementation. One potential fix would be to provide some protocol for these
// nodes to converse with.
if ([element isKindOfClass:[TTStyledLinkNode class]]) {
TTOpenURL([(TTStyledLinkNode*)element URL]);
TTOpenURLFromView([(TTStyledLinkNode*)element URL], self);

} else if ([element isKindOfClass:[TTStyledButtonNode class]]) {
TTOpenURL([(TTStyledButtonNode*)element URL]);
TTOpenURLFromView([(TTStyledButtonNode*)element URL], self);


} else {
Expand Down
2 changes: 1 addition & 1 deletion src/Three20UI/Sources/TTTableViewController.m
Expand Up @@ -861,7 +861,7 @@ - (void)didSelectObject:(id)object atIndexPath:(NSIndexPath*)indexPath {
if ([object respondsToSelector:@selector(URLValue)]) {
NSString* URL = [object URLValue];
if (URL) {
TTOpenURL(URL);
TTOpenURLFromView(URL, self.view);
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Three20UI/Sources/TTTableViewDelegate.m
Expand Up @@ -118,7 +118,7 @@ - (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)
if ([object isKindOfClass:[TTTableLinkedItem class]]) {
TTTableLinkedItem* item = object;
if (item.URL && [_controller shouldOpenURL:item.URL]) {
TTOpenURL(item.URL);
TTOpenURLFromView(item.URL, tableView);

} else if (item.delegate && item.selector) {
[item.delegate performSelector:item.selector withObject:object];
Expand Down Expand Up @@ -158,7 +158,7 @@ - (void)tableView:(UITableView*)tableView
if ([object isKindOfClass:[TTTableLinkedItem class]]) {
TTTableLinkedItem* item = object;
if (item.accessoryURL && [_controller shouldOpenURL:item.accessoryURL]) {
TTOpenURL(item.accessoryURL);
TTOpenURLFromView(item.accessoryURL, tableView);
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/Three20UI/Sources/TTTextBarController.m
Expand Up @@ -29,6 +29,7 @@
// UICommon
#import "Three20UICommon/TTGlobalUICommon.h"
#import "Three20UICommon/UIViewControllerAdditions.h"
#import "Three20UICommon/UIView+TTUICommon.h"

// Style
#import "Three20Style/TTGlobalStyle.h"
Expand Down
7 changes: 4 additions & 3 deletions src/Three20UI/Sources/UINSStringAdditions.m
Expand Up @@ -48,9 +48,10 @@ - (void)openURL {
///////////////////////////////////////////////////////////////////////////////////////////////////
- (void)openURLFromButton:(UIView*)button {
NSDictionary* query = [NSDictionary dictionaryWithObjectsAndKeys:button, @"__target__", nil];
[[TTNavigator navigator] openURLAction:[[[TTURLAction actionWithURLPath: self]
applyQuery: query]
applyAnimated: YES]];
[[TTBaseNavigator navigatorForView:button]
openURLAction:[[[TTURLAction actionWithURLPath: self]
applyQuery: query]
applyAnimated: YES]];
}


Expand Down
12 changes: 0 additions & 12 deletions src/Three20UI/Sources/UIViewAdditions.m
Expand Up @@ -524,16 +524,4 @@ - (void)dismissAsKeyboard:(BOOL)animated {
}


///////////////////////////////////////////////////////////////////////////////////////////////////
- (UIViewController*)viewController {
for (UIView* next = [self superview]; next; next = next.superview) {
UIResponder* nextResponder = [next nextResponder];
if ([nextResponder isKindOfClass:[UIViewController class]]) {
return (UIViewController*)nextResponder;
}
}
return nil;
}


@end

0 comments on commit aa52d07

Please sign in to comment.