added settings menu and persistent storage for settings
This commit is contained in:
@@ -48,6 +48,11 @@
|
||||
FB8946EC19F6AFE400339C8A /* libssl.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E119F6AFB800339C8A /* libssl.a */; };
|
||||
FB8946ED19F6AFE800339C8A /* libopus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946EA19F6AFB800339C8A /* libopus.a */; };
|
||||
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppManager.m */; };
|
||||
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
|
||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
|
||||
FBD3495B1A004411002D2A60 /* Hosts.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495A1A004411002D2A60 /* Hosts.m */; };
|
||||
FBD3495E1A004412002D2A60 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495D1A004412002D2A60 /* Settings.m */; };
|
||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD349611A0089F6002D2A60 /* DataManager.m */; };
|
||||
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86DF19F7A837001C18A8 /* UIComputerView.m */; };
|
||||
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E519F82297001C18A8 /* UIAppView.m */; };
|
||||
FBDE86E919F82315001C18A8 /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E819F82315001C18A8 /* App.m */; };
|
||||
@@ -217,6 +222,17 @@
|
||||
FB8946EA19F6AFB800339C8A /* libopus.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libopus.a; sourceTree = "<group>"; };
|
||||
FBD3494119FC9C04002D2A60 /* AppManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppManager.h; sourceTree = "<group>"; };
|
||||
FBD3494219FC9C04002D2A60 /* AppManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppManager.m; sourceTree = "<group>"; };
|
||||
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SettingsViewController.h; sourceTree = "<group>"; };
|
||||
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SettingsViewController.m; sourceTree = "<group>"; };
|
||||
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; };
|
||||
FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = "<group>"; };
|
||||
FBD349571A003F05002D2A60 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
||||
FBD349591A004411002D2A60 /* Hosts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Hosts.h; path = Database/Hosts.h; sourceTree = "<group>"; };
|
||||
FBD3495A1A004411002D2A60 /* Hosts.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Hosts.m; path = Database/Hosts.m; sourceTree = "<group>"; };
|
||||
FBD3495C1A004412002D2A60 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Settings.h; path = Database/Settings.h; sourceTree = "<group>"; };
|
||||
FBD3495D1A004412002D2A60 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Settings.m; path = Database/Settings.m; sourceTree = "<group>"; };
|
||||
FBD349601A0089F6002D2A60 /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataManager.h; path = Database/DataManager.h; sourceTree = "<group>"; };
|
||||
FBD349611A0089F6002D2A60 /* DataManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DataManager.m; path = Database/DataManager.m; sourceTree = "<group>"; };
|
||||
FBDE86DE19F7A837001C18A8 /* UIComputerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIComputerView.h; sourceTree = "<group>"; };
|
||||
FBDE86DF19F7A837001C18A8 /* UIComputerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIComputerView.m; sourceTree = "<group>"; };
|
||||
FBDE86E419F82297001C18A8 /* UIAppView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAppView.h; sourceTree = "<group>"; };
|
||||
@@ -289,6 +305,7 @@
|
||||
FB290CF019B2C406004C83CF /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD349571A003F05002D2A60 /* libsqlite3.dylib */,
|
||||
FB89468F19F6AFB800339C8A /* libs */,
|
||||
FB7E794319C8B71B00A15F68 /* libiconv.dylib */,
|
||||
FB290DC319B2E98F004C83CF /* libxml2.dylib */,
|
||||
@@ -311,6 +328,7 @@
|
||||
FB89461519F646E200339C8A /* Stream */,
|
||||
FB89461E19F646E200339C8A /* Utility */,
|
||||
FB89462319F646E200339C8A /* ViewControllers */,
|
||||
FBD3495F1A004453002D2A60 /* Database */,
|
||||
FB290CFA19B2C406004C83CF /* Supporting Files */,
|
||||
FB290D0219B2C406004C83CF /* AppDelegate.h */,
|
||||
FB290D0319B2C406004C83CF /* AppDelegate.m */,
|
||||
@@ -424,10 +442,14 @@
|
||||
FB89462319F646E200339C8A /* ViewControllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */,
|
||||
FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */,
|
||||
FB89462419F646E200339C8A /* MainFrameViewController.h */,
|
||||
FB89462519F646E200339C8A /* MainFrameViewController.m */,
|
||||
FB89462619F646E200339C8A /* StreamFrameViewController.h */,
|
||||
FB89462719F646E200339C8A /* StreamFrameViewController.m */,
|
||||
FBD3494E19FF2174002D2A60 /* SettingsViewController.h */,
|
||||
FBD3494F19FF2174002D2A60 /* SettingsViewController.m */,
|
||||
);
|
||||
path = ViewControllers;
|
||||
sourceTree = "<group>";
|
||||
@@ -593,6 +615,19 @@
|
||||
path = lib;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FBD3495F1A004453002D2A60 /* Database */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FBD3495C1A004412002D2A60 /* Settings.h */,
|
||||
FBD3495D1A004412002D2A60 /* Settings.m */,
|
||||
FBD349591A004411002D2A60 /* Hosts.h */,
|
||||
FBD3495A1A004411002D2A60 /* Hosts.m */,
|
||||
FBD349601A0089F6002D2A60 /* DataManager.h */,
|
||||
FBD349611A0089F6002D2A60 /* DataManager.m */,
|
||||
);
|
||||
name = Database;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
|
||||
/* Begin PBXNativeTarget section */
|
||||
@@ -713,6 +748,7 @@
|
||||
files = (
|
||||
FB290D0719B2C406004C83CF /* Limelight.xcdatamodeld in Sources */,
|
||||
FB89463219F646E200339C8A /* VideoDecoderRenderer.m in Sources */,
|
||||
FBD3495E1A004412002D2A60 /* Settings.m in Sources */,
|
||||
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */,
|
||||
FB89463419F646E200339C8A /* Utils.m in Sources */,
|
||||
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */,
|
||||
@@ -722,9 +758,12 @@
|
||||
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
|
||||
FBDE86E919F82315001C18A8 /* App.m in Sources */,
|
||||
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
|
||||
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
|
||||
FB89462C19F646E200339C8A /* HttpManager.m in Sources */,
|
||||
FB89462D19F646E200339C8A /* MDNSManager.m in Sources */,
|
||||
FB89462B19F646E200339C8A /* StreamView.m in Sources */,
|
||||
FBD3495B1A004411002D2A60 /* Hosts.m in Sources */,
|
||||
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
||||
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
|
||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
||||
@@ -732,6 +771,7 @@
|
||||
FB290D0019B2C406004C83CF /* main.m in Sources */,
|
||||
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */,
|
||||
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
||||
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
||||
@@ -18,5 +18,6 @@
|
||||
|
||||
- (void)saveContext;
|
||||
- (NSURL *)applicationDocumentsDirectory;
|
||||
- (NSURL*) getStoreURL;
|
||||
|
||||
@end
|
||||
|
||||
@@ -100,7 +100,7 @@ static NSOperationQueue* mainQueue;
|
||||
return _persistentStoreCoordinator;
|
||||
}
|
||||
|
||||
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Limelight_iOS.sqlite"];
|
||||
NSURL *storeURL = [self getStoreURL];
|
||||
|
||||
NSError *error = nil;
|
||||
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
|
||||
@@ -143,4 +143,8 @@ static NSOperationQueue* mainQueue;
|
||||
return [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
|
||||
}
|
||||
|
||||
- (NSURL*) getStoreURL {
|
||||
return [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Limelight_iOS.sqlite"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
//
|
||||
// DataManager.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "Settings.h"
|
||||
#import "AppDelegate.h"
|
||||
#import "Hosts.h"
|
||||
|
||||
@interface DataManager : NSObject
|
||||
|
||||
@property (strong, nonatomic) AppDelegate* appDelegate;
|
||||
|
||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width;
|
||||
- (Settings*) retrieveSettings;
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,65 @@
|
||||
//
|
||||
// DataManager.m
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "DataManager.h"
|
||||
|
||||
@implementation DataManager
|
||||
static NSInteger DEFAULT_BITRATE = 10000;
|
||||
static NSInteger DEFAULT_FRAMERATE = 60;
|
||||
static NSInteger DEFAULT_HEIGHT = 720;
|
||||
static NSInteger DEFAULT_WIDTH = 1280;
|
||||
|
||||
- (id) init {
|
||||
self = [super init];
|
||||
self.appDelegate = [[UIApplication sharedApplication] delegate];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width {
|
||||
Settings* settingsToSave = [self retrieveSettings];
|
||||
settingsToSave.framerate = [NSNumber numberWithInteger:framerate];
|
||||
settingsToSave.bitrate = [NSNumber numberWithInteger:bitrate];
|
||||
settingsToSave.height = [NSNumber numberWithInteger:height];
|
||||
settingsToSave.width = [NSNumber numberWithInteger:width];
|
||||
[self saveSettings:settingsToSave];
|
||||
}
|
||||
|
||||
- (Settings*) retrieveSettings {
|
||||
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
|
||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Settings" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
[fetchRequest setEntity:entity];
|
||||
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
|
||||
|
||||
NSError* error;
|
||||
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
|
||||
|
||||
if (fetchedRecords.count == 0) {
|
||||
// create a new settings object with the default values
|
||||
Settings* settings = [[Settings alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||
settings.framerate = [NSNumber numberWithInteger:DEFAULT_FRAMERATE];
|
||||
settings.bitrate = [NSNumber numberWithInteger:DEFAULT_BITRATE];
|
||||
settings.height = [NSNumber numberWithInteger:DEFAULT_HEIGHT];
|
||||
settings.width = [NSNumber numberWithInteger:DEFAULT_WIDTH];
|
||||
return settings;
|
||||
} else {
|
||||
// we should only ever have 1 settings object stored
|
||||
return [fetchedRecords objectAtIndex:0];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) saveSettings:(Settings*)settings {
|
||||
NSError* error;
|
||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
||||
NSLog(@"ERROR: Unable to save settings to database");
|
||||
}
|
||||
|
||||
[self.appDelegate saveContext];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,18 @@
|
||||
//
|
||||
// Hosts.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
|
||||
@interface Hosts : NSManagedObject
|
||||
|
||||
@property (nonatomic, retain) NSString * address;
|
||||
@property (nonatomic, retain) NSString * name;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,17 @@
|
||||
//
|
||||
// Hosts.m
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Hosts.h"
|
||||
|
||||
|
||||
@implementation Hosts
|
||||
|
||||
@dynamic address;
|
||||
@dynamic name;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Settings.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreData/CoreData.h>
|
||||
|
||||
|
||||
@interface Settings : NSManagedObject
|
||||
|
||||
@property (nonatomic, retain) NSNumber * bitrate;
|
||||
@property (nonatomic, retain) NSNumber * framerate;
|
||||
@property (nonatomic, retain) NSNumber * height;
|
||||
@property (nonatomic, retain) NSNumber * width;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,19 @@
|
||||
//
|
||||
// Settings.m
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/28/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Settings.h"
|
||||
|
||||
|
||||
@implementation Settings
|
||||
|
||||
@dynamic bitrate;
|
||||
@dynamic framerate;
|
||||
@dynamic height;
|
||||
@dynamic width;
|
||||
|
||||
@end
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 31 KiB |
+3
-5
@@ -2,18 +2,16 @@
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "Left4Dead2-2.jpg"
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "Left4Dead2.jpg"
|
||||
"filename" : "settings_2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "Left4Dead2-1.jpg"
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.7 KiB |
@@ -1,4 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model name="Test1.xcdatamodel" userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="1" systemVersion="11A491" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<elements/>
|
||||
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="6252" systemVersion="14A388a" minimumToolsVersion="Automatic" macOSVersion="Automatic" iOSVersion="Automatic">
|
||||
<entity name="Hosts" representedClassName="Hosts" syncable="YES">
|
||||
<attribute name="address" optional="YES" attributeType="String" syncable="YES"/>
|
||||
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||
</entity>
|
||||
<entity name="Settings" representedClassName="Settings" syncable="YES">
|
||||
<attribute name="bitrate" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="framerate" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="height" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
<attribute name="width" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Hosts" positionX="-63" positionY="-18" width="128" height="75"/>
|
||||
<element name="Settings" positionX="142" positionY="-36" width="128" height="103"/>
|
||||
</elements>
|
||||
</model>
|
||||
@@ -13,8 +13,10 @@
|
||||
#import "UIComputerView.h"
|
||||
#import "UIAppView.h"
|
||||
#import "AppManager.h"
|
||||
#import "SWRevealViewController.h"
|
||||
|
||||
@interface MainFrameViewController : UIViewController <MDNSCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate>
|
||||
@interface MainFrameViewController : UIViewController <MDNSCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate>
|
||||
@property (strong, nonatomic) IBOutlet UIBarButtonItem *settingsSidebarButton;
|
||||
|
||||
+ (StreamConfiguration*) getStreamConfiguration;
|
||||
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#import "UIComputerView.h"
|
||||
#import "UIAppView.h"
|
||||
#import "App.h"
|
||||
#import "SettingsViewController.h"
|
||||
#import "DataManager.h"
|
||||
#import "Settings.h"
|
||||
|
||||
@implementation MainFrameViewController {
|
||||
NSOperationQueue* _opQueue;
|
||||
@@ -134,60 +137,58 @@ static StreamConfiguration* streamConfig;
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: actually allow the user to choose the config
|
||||
unsigned long selectedConf = 1;
|
||||
NSLog(@"selectedConf: %ld", selectedConf);
|
||||
switch (selectedConf) {
|
||||
case 0:
|
||||
streamConfig.width = 1280;
|
||||
streamConfig.height = 720;
|
||||
streamConfig.frameRate = 30;
|
||||
streamConfig.bitRate = 5000;
|
||||
break;
|
||||
default:
|
||||
case 1:
|
||||
streamConfig.width = 1280;
|
||||
streamConfig.height = 720;
|
||||
streamConfig.frameRate = 60;
|
||||
streamConfig.bitRate = 10000;
|
||||
break;
|
||||
case 2:
|
||||
streamConfig.width = 1920;
|
||||
streamConfig.height = 1080;
|
||||
streamConfig.frameRate = 30;
|
||||
streamConfig.bitRate = 10000;
|
||||
break;
|
||||
case 3:
|
||||
streamConfig.width = 1920;
|
||||
streamConfig.height = 1080;
|
||||
streamConfig.frameRate = 60;
|
||||
streamConfig.bitRate = 20000;
|
||||
break;
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
Settings* streamSettings = [dataMan retrieveSettings];
|
||||
|
||||
streamConfig.frameRate = [streamSettings.framerate intValue];
|
||||
streamConfig.bitRate = [streamSettings.bitrate intValue];
|
||||
streamConfig.height = [streamSettings.height intValue];
|
||||
streamConfig.width = [streamSettings.width intValue];
|
||||
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||
}
|
||||
|
||||
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position {
|
||||
// If we moved back to the center position, we should save the settings
|
||||
if (position == FrontViewPositionLeft) {
|
||||
[(SettingsViewController*)[revealController rearViewController] saveSettings];
|
||||
}
|
||||
NSLog(@"StreamConfig: %@, %d, %dx%dx%d at %d Mbps", streamConfig.host, streamConfig.hostAddr, streamConfig.width, streamConfig.height, streamConfig.frameRate, streamConfig.bitRate);
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:self];
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
NSArray* streamConfigVals = [[NSArray alloc] initWithObjects:@"1280x720 (30Hz)", @"1280x720 (60Hz)", @"1920x1080 (30Hz)", @"1920x1080 (60Hz)",nil];
|
||||
|
||||
// Change button color
|
||||
_settingsSidebarButton.tintColor = [UIColor colorWithRed:.2 green:.9 blue:0.f alpha:1.f];
|
||||
|
||||
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
|
||||
_settingsSidebarButton.target = self.revealViewController;
|
||||
_settingsSidebarButton.action = @selector(revealToggle:);
|
||||
|
||||
// Set the gesture
|
||||
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
|
||||
|
||||
[self.revealViewController setDelegate:self];
|
||||
|
||||
//NSArray* streamConfigVals = [[NSArray alloc] initWithObjects:@"1280x720 (30Hz)", @"1280x720 (60Hz)", @"1920x1080 (30Hz)", @"1920x1080 (60Hz)",nil];
|
||||
|
||||
_opQueue = [[NSOperationQueue alloc] init];
|
||||
[CryptoManager generateKeyPairUsingSSl];
|
||||
_uniqueId = [CryptoManager getUniqueID];
|
||||
_cert = [CryptoManager readCertFromFile];
|
||||
|
||||
// Initialize the host picker list
|
||||
// Only initialize the host picker list once
|
||||
if (hostList == nil) {
|
||||
hostList = [[NSMutableSet alloc] init];
|
||||
}
|
||||
|
||||
[self setAutomaticallyAdjustsScrollViewInsets:NO];
|
||||
|
||||
hostScrollView = [[UIScrollView alloc] init];
|
||||
hostScrollView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height / 2);
|
||||
hostScrollView.frame = CGRectMake(0, self.navigationController.navigationBar.frame.origin.y + self.navigationController.navigationBar.frame.size.height, self.view.frame.size.width, self.view.frame.size.height / 2);
|
||||
[hostScrollView setShowsHorizontalScrollIndicator:NO];
|
||||
|
||||
|
||||
appScrollView = [[UIScrollView alloc] init];
|
||||
appScrollView.frame = CGRectMake(0, hostScrollView.frame.size.height, self.view.frame.size.width, self.view.frame.size.height / 2);
|
||||
[appScrollView setShowsHorizontalScrollIndicator:NO];
|
||||
@@ -199,7 +200,8 @@ static StreamConfiguration* streamConfig;
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[super viewDidAppear:animated];
|
||||
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
||||
_mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
||||
[_mDNSManager searchForHosts];
|
||||
}
|
||||
|
||||
+418
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013 Joan Lluch <[email protected]>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Early code inspired on a similar class by Philip Kluz ([email protected])
|
||||
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
RELEASE NOTES
|
||||
|
||||
|
||||
Version 2.3.0 (Current Version)
|
||||
|
||||
- StoryBoard initializing bug fix
|
||||
- Minor Code refactoring
|
||||
|
||||
Version 2.2.0
|
||||
|
||||
- State Restoration support.
|
||||
- Reverted panGestureRecognizer implementation to before v2.1.0 (works better).
|
||||
- New properties 'toggleAnimationType', 'springDampingRatio'. Default reveal animation is 'Spring'
|
||||
- New property 'frontViewShadowColor'
|
||||
- New properties 'clipsViewsToBounds' and '_extendedPointInsideHit'
|
||||
- New delegate methods for finer control of front view location in the overdraw area, as long as deprecation note on former delegate methods
|
||||
- Other minor changes that should not affect current implementations
|
||||
|
||||
Version 2.1.0
|
||||
|
||||
- Removed SWDirectionPanGestureRecognizer. Horizontal panning is filtered on the shouldBegin delegate. This is cleaner, I hope it does not break previous funcionality
|
||||
- Took a cleaner approach to storyboard support. SWRevealViewControllerSegue is now deprecated and you should use SWRevealViewControllerSegueSetController and SWRevealViewControllerSeguePushController instead.
|
||||
- A minor change on the autoresizingMask of the internal views to fix a glitch on iOS8. This should not affect iOS7
|
||||
|
||||
Version 2.0.2
|
||||
|
||||
- Added new delegates for better control of gesture recognizers
|
||||
|
||||
Version 2.0.1
|
||||
|
||||
- Fix: draggableBorderWidth now correctly handles the cases where one of the rear controllers is not provided
|
||||
- Fix: the shadow related properties are now granted at any time after view load, not just after initialization.
|
||||
|
||||
Version 2.0.0
|
||||
|
||||
- Dropped support for iOS6 and earlier. This version will only work on iOS7
|
||||
|
||||
- The method setFrontViewController:animated: does not longer perform a full reveal animation. Instead it just replaces the frontViewController in
|
||||
its current position. Use the new pushFrontViewController:animated: method to perform a replacement of the front controlles with reveal animation
|
||||
as in the previous version
|
||||
|
||||
IMPORTANT: You must replace all calls to setFrontViewController:animated by calls to pushFrontViewController:animated to prevent breaking
|
||||
functionality on existing projects.
|
||||
|
||||
- Added support for animated replacement of child controllers: setRearViewController, setFrontViewController, setRightViewController now have animated versions.
|
||||
|
||||
- The new 'replaceViewAnimationDuration' property sets the default duration of child viewController replacement.
|
||||
|
||||
- Added the following new delegate methods
|
||||
revealController:willAddViewController:forOperation:animated:
|
||||
revealController:didAddViewController:forOperation:animated:
|
||||
|
||||
- The class also supports custom UIViewControllerAnimatedTransitioning related with the replacement of child viewControllers.
|
||||
You can implement the following new delegate method: revealController:animationControllerForOperation:fromViewController:toViewController:
|
||||
and provide an object conforming to UIViewControllerAnimatedTransitioning to implement custom animations.
|
||||
|
||||
Version 1.1.3
|
||||
|
||||
- Reverted the supportedInterfaceOrientations to the default behavior. This is consistent with Apple provided controllers
|
||||
|
||||
- The presentFrontViewHierarchically now dynamically takes into account the smaller header height of bars on iPhone landscape orientation
|
||||
|
||||
Version 1.1.2
|
||||
|
||||
- The status bar style and appearance are now handled in sync with the class animations.
|
||||
You can implement the methods preferredStatusBarStyle and prefersStatusBarHidden on your child controllers to define the desired appearance
|
||||
|
||||
- The loadView method now calls a method, loadStoryboardControllers, just for the purpose of loading child controllers from a storyboard.
|
||||
You can override this method and remove the @try @catch statements if you want the debugger not to stop at them in case you have set an exception breakpoint.
|
||||
|
||||
Version 1.1.1
|
||||
|
||||
- You can now get a tapGestureRecognizer from the class. See the tapGestureRecognizer method for more information.
|
||||
|
||||
- Both the panGestureRecognizer and the tapGestureRecognizer are now attached to the revealViewController's front content view
|
||||
by default, so they will start working just by calling their access methods even if you do not attach them to any of your views.
|
||||
This enables you to dissable interactions on your views -for example based on position- without breaking normal gesture behavior.
|
||||
|
||||
- Corrected a bug that caused a crash on iOS6 and earlier.
|
||||
|
||||
Version 1.1.0
|
||||
|
||||
- The method setFrontViewController:animated now performs the correct animations both for left and right controllers.
|
||||
|
||||
- The class now automatically handles the status bar appearance depending on the currently shown child controller.
|
||||
|
||||
Version 1.0.8
|
||||
|
||||
- Support for constant width frontView by setting a negative value to reveal widths. See properties rearViewRevealWidth and rightViewRevealWidth
|
||||
|
||||
- Support for draggableBorderWidth. See property of the same name.
|
||||
|
||||
- The Pan gesture recongnizer can be disabled by implementing the following delegate method and returning NO
|
||||
revealControllerPanGestureShouldBegin:
|
||||
|
||||
- Added the ability to track pan gesture reveal progress through the following new delegate methods
|
||||
revealController:panGestureBeganFromLocation:progress:
|
||||
revealController:panGestureMovedToLocation:progress:
|
||||
revealController:panGestureEndedToLocation:progress:
|
||||
|
||||
Previous Versions
|
||||
|
||||
- No release notes were updated for previous versions.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@class SWRevealViewController;
|
||||
@protocol SWRevealViewControllerDelegate;
|
||||
|
||||
#pragma mark - SWRevealViewController Class
|
||||
|
||||
// Enum values for setFrontViewPosition:animated:
|
||||
typedef NS_ENUM( NSInteger, FrontViewPosition)
|
||||
{
|
||||
// Front controller is removed from view. Animated transitioning from this state will cause the same
|
||||
// effect than animating from FrontViewPositionLeftSideMost. Use this instead of FrontViewPositionLeftSideMost when
|
||||
// you want to remove the front view controller view from the view hierarchy.
|
||||
FrontViewPositionLeftSideMostRemoved,
|
||||
|
||||
// Left most position, front view is presented left-offseted by rightViewRevealWidth+rigthViewRevealOverdraw
|
||||
FrontViewPositionLeftSideMost,
|
||||
|
||||
// Left position, front view is presented left-offseted by rightViewRevealWidth
|
||||
FrontViewPositionLeftSide,
|
||||
|
||||
// Center position, rear view is hidden behind front controller
|
||||
FrontViewPositionLeft,
|
||||
|
||||
// Right possition, front view is presented right-offseted by rearViewRevealWidth
|
||||
FrontViewPositionRight,
|
||||
|
||||
// Right most possition, front view is presented right-offseted by rearViewRevealWidth+rearViewRevealOverdraw
|
||||
FrontViewPositionRightMost,
|
||||
|
||||
// Front controller is removed from view. Animated transitioning from this state will cause the same
|
||||
// effect than animating from FrontViewPositionRightMost. Use this instead of FrontViewPositionRightMost when
|
||||
// you intent to remove the front controller view from the view hierarchy.
|
||||
FrontViewPositionRightMostRemoved,
|
||||
|
||||
};
|
||||
|
||||
// Enum values for toggleAnimationType
|
||||
typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType)
|
||||
{
|
||||
SWRevealToggleAnimationTypeSpring, // <- produces a spring based animation
|
||||
SWRevealToggleAnimationTypeEaseOut, // <- produces an ease out curve animation
|
||||
};
|
||||
|
||||
|
||||
@interface SWRevealViewController : UIViewController
|
||||
|
||||
/* Basic API */
|
||||
|
||||
// Object instance init and rear view setting
|
||||
- (id)initWithRearViewController:(UIViewController *)rearViewController frontViewController:(UIViewController *)frontViewController;
|
||||
|
||||
// Rear view controller, can be nil if not used
|
||||
@property (nonatomic) UIViewController *rearViewController;
|
||||
- (void)setRearViewController:(UIViewController *)rearViewController animated:(BOOL)animated;
|
||||
|
||||
// Optional right view controller, can be nil if not used
|
||||
@property (nonatomic) UIViewController *rightViewController;
|
||||
- (void)setRightViewController:(UIViewController *)rightViewController animated:(BOOL)animated;
|
||||
|
||||
// Front view controller, can be nil on initialization but must be supplied by the time the view is loaded
|
||||
@property (nonatomic) UIViewController *frontViewController;
|
||||
- (void)setFrontViewController:(UIViewController *)frontViewController animated:(BOOL)animated;
|
||||
|
||||
// Sets the frontViewController using a default set of chained animations consisting on moving the
|
||||
// presented frontViewController to the right most possition, replacing it, and moving it back to the left position
|
||||
- (void)pushFrontViewController:(UIViewController *)frontViewController animated:(BOOL)animated;
|
||||
|
||||
// Sets the frontViewController position. You can call the animated version several times with different
|
||||
// positions to obtain a set of animations that will be performed in order one after the other.
|
||||
@property (nonatomic) FrontViewPosition frontViewPosition;
|
||||
- (void)setFrontViewPosition:(FrontViewPosition)frontViewPosition animated:(BOOL)animated;
|
||||
|
||||
// The following methods are meant to be directly connected to the action method of a button
|
||||
// to perform user triggered postion change of the controller views. This is ussually added to a
|
||||
// button on top left or right of the frontViewController
|
||||
- (IBAction)revealToggle:(id)sender;
|
||||
- (IBAction)rightRevealToggle:(id)sender; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// Toogles the current state of the front controller between Left or Right and fully visible
|
||||
// Use setFrontViewPosition to set a particular position
|
||||
- (void)revealToggleAnimated:(BOOL)animated;
|
||||
- (void)rightRevealToggleAnimated:(BOOL)animated; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// The following method will provide a panGestureRecognizer suitable to be added to any view
|
||||
// in order to perform usual drag and swipe gestures to reveal the rear views. This is usually added to the top bar
|
||||
// of a front controller, but it can be added to your frontViewController view or to the reveal controller view to provide full screen panning.
|
||||
// By default, the panGestureRecognizer is added to the view containing the front controller view. To keep this default behavior
|
||||
// you still need to call this method, just don't add it to any of your views. The default setup allows you to dissable
|
||||
// user interactions on your controller views without affecting the recognizer.
|
||||
- (UIPanGestureRecognizer*)panGestureRecognizer;
|
||||
|
||||
// The following method will provide a tapGestureRecognizer suitable to be added to any view on the frontController
|
||||
// for concealing the rear views. By default no tap recognizer is created or added to any view, however if you call this method after
|
||||
// the controller's view has been loaded the recognizer is added to the reveal controller's front container view.
|
||||
// Thus, you can disable user interactions on your frontViewController view without affecting the tap recognizer.
|
||||
- (UITapGestureRecognizer*)tapGestureRecognizer;
|
||||
|
||||
/* The following properties are provided for further customization, they are set to default values on initialization,
|
||||
you do not generally have to set them */
|
||||
|
||||
// Defines how much of the rear or right view is shown, default is 260.
|
||||
// Negative values indicate that the reveal width should be computed by substracting the full front view width,
|
||||
// so the revealed frontView width is kept constant when bounds change as opposed to the rear or right width.
|
||||
@property (nonatomic) CGFloat rearViewRevealWidth;
|
||||
@property (nonatomic) CGFloat rightViewRevealWidth; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// Defines how much of an overdraw can occur when dragging further than 'rearViewRevealWidth', default is 60.
|
||||
@property (nonatomic) CGFloat rearViewRevealOverdraw;
|
||||
@property (nonatomic) CGFloat rightViewRevealOverdraw; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// Defines how much displacement is applied to the rear view when animating or dragging the front view, default is 40.
|
||||
@property (nonatomic) CGFloat rearViewRevealDisplacement;
|
||||
@property (nonatomic) CGFloat rightViewRevealDisplacement; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// Defines a width on the border of the view attached to the panGesturRecognizer where the gesture is allowed,
|
||||
// default is 0 which means no restriction.
|
||||
@property (nonatomic) CGFloat draggableBorderWidth;
|
||||
|
||||
// If YES (the default) the controller will bounce to the Left position when dragging further than 'rearViewRevealWidth'
|
||||
@property (nonatomic) BOOL bounceBackOnOverdraw;
|
||||
@property (nonatomic) BOOL bounceBackOnLeftOverdraw; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// If YES (default is NO) the controller will allow permanent dragging up to the rightMostPosition
|
||||
@property (nonatomic) BOOL stableDragOnOverdraw;
|
||||
@property (nonatomic) BOOL stableDragOnLeftOverdraw; // <-- simetric implementation of the above for the rightViewController
|
||||
|
||||
// If YES (default is NO) the front view controller will be ofsseted vertically by the height of a navigation bar.
|
||||
// Use this on iOS7 when you add an instance of RevealViewController as a child of a UINavigationController (or another SWRevealViewController)
|
||||
// and you want the front view controller to be presented below the navigation bar of its UINavigationController grand parent.
|
||||
// The rearViewController will still appear full size and blurred behind the navigation bar of its UINavigationController grand parent
|
||||
@property (nonatomic) BOOL presentFrontViewHierarchically;
|
||||
|
||||
// Velocity required for the controller to toggle its state based on a swipe movement, default is 250
|
||||
@property (nonatomic) CGFloat quickFlickVelocity;
|
||||
|
||||
// Duration for the revealToggle animation, default is 0.25
|
||||
@property (nonatomic) NSTimeInterval toggleAnimationDuration;
|
||||
|
||||
// Animation type, default is SWRevealToggleAnimationTypeSpring
|
||||
@property (nonatomic) SWRevealToggleAnimationType toggleAnimationType;
|
||||
|
||||
// When animation type is SWRevealToggleAnimationTypeSpring determines the damping ratio, default is 1
|
||||
@property (nonatomic) CGFloat springDampingRatio;
|
||||
|
||||
// Duration for animated replacement of view controllers
|
||||
@property (nonatomic) NSTimeInterval replaceViewAnimationDuration;
|
||||
|
||||
// Defines the radius of the front view's shadow, default is 2.5f
|
||||
@property (nonatomic) CGFloat frontViewShadowRadius;
|
||||
|
||||
// Defines the radius of the front view's shadow offset default is {0.0f,2.5f}
|
||||
@property (nonatomic) CGSize frontViewShadowOffset;
|
||||
|
||||
// Defines the front view's shadow opacity, default is 1.0f
|
||||
@property (nonatomic) CGFloat frontViewShadowOpacity;
|
||||
|
||||
// Defines the front view's shadow color, default is blackColor
|
||||
@property (nonatomic) UIColor *frontViewShadowColor;
|
||||
|
||||
// Defines whether the controller should clip subviews to its view bounds. Default is NO.
|
||||
// Set this to YES when you are presenting this controller as a non full-screen child of a
|
||||
// custom container controller which does not explicitly clips its subviews.
|
||||
@property (nonatomic) BOOL clipsViewsToBounds;
|
||||
|
||||
// Defines whether your views clicable area extends beyond the bounds of this controller. Default is NO.
|
||||
// Set this to YES if you are presenting this controller as a non full-screen child of a custom container and you are not
|
||||
// clipping your front view to this controller bounds.
|
||||
@property (nonatomic) BOOL extendsPointInsideHit;
|
||||
|
||||
/* The class properly handles all the relevant calls to appearance methods on the contained controllers.
|
||||
Moreover you can assign a delegate to let the class inform you on positions and animation activity */
|
||||
|
||||
// Delegate
|
||||
@property (nonatomic,weak) id<SWRevealViewControllerDelegate> delegate;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWRevealViewControllerDelegate Protocol
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SWRevealControllerOperationNone,
|
||||
SWRevealControllerOperationReplaceRearController,
|
||||
SWRevealControllerOperationReplaceFrontController,
|
||||
SWRevealControllerOperationReplaceRightController,
|
||||
|
||||
} SWRevealControllerOperation;
|
||||
|
||||
|
||||
@protocol SWRevealViewControllerDelegate<NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// The following delegate methods will be called before and after the front view moves to a position
|
||||
- (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position;
|
||||
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position;
|
||||
|
||||
// This will be called inside the reveal animation, thus you can use it to place your own code that will be animated in sync
|
||||
- (void)revealController:(SWRevealViewController *)revealController animateToPosition:(FrontViewPosition)position;
|
||||
|
||||
// Implement this to return NO when you want the pan gesture recognizer to be ignored
|
||||
- (BOOL)revealControllerPanGestureShouldBegin:(SWRevealViewController *)revealController;
|
||||
|
||||
// Implement this to return NO when you want the tap gesture recognizer to be ignored
|
||||
- (BOOL)revealControllerTapGestureShouldBegin:(SWRevealViewController *)revealController;
|
||||
|
||||
// Implement this to return YES if you want other gesture recognizer to share touch events with the pan gesture
|
||||
- (BOOL)revealController:(SWRevealViewController *)revealController
|
||||
panGestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
|
||||
|
||||
// Implement this to return YES if you want other gesture recognizer to share touch events with the tap gesture
|
||||
- (BOOL)revealController:(SWRevealViewController *)revealController
|
||||
tapGestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
|
||||
|
||||
// Called when the gestureRecognizer began and ended
|
||||
- (void)revealControllerPanGestureBegan:(SWRevealViewController *)revealController;
|
||||
- (void)revealControllerPanGestureEnded:(SWRevealViewController *)revealController;
|
||||
|
||||
// The following methods provide a means to track the evolution of the gesture recognizer.
|
||||
// The 'location' parameter is the X origin coordinate of the front view as the user drags it
|
||||
// The 'progress' parameter is a number ranging from 0 to 1 indicating the front view location relative to the
|
||||
// rearRevealWidth or rightRevealWidth. 1 is fully revealed, dragging ocurring in the overDraw region will result in values above 1.
|
||||
// The 'overProgress' parameter is a number ranging from 0 to 1 indicating the front view location relative to the
|
||||
// overdraw region. 0 is fully revealed, 1 is fully overdrawn. Negative values occur inside the normal reveal region
|
||||
- (void)revealController:(SWRevealViewController *)revealController panGestureBeganFromLocation:(CGFloat)location progress:(CGFloat)progress overProgress:(CGFloat)overProgress;
|
||||
- (void)revealController:(SWRevealViewController *)revealController panGestureMovedToLocation:(CGFloat)location progress:(CGFloat)progress overProgress:(CGFloat)overProgress;
|
||||
- (void)revealController:(SWRevealViewController *)revealController panGestureEndedToLocation:(CGFloat)location progress:(CGFloat)progress overProgress:(CGFloat)overProgress;
|
||||
|
||||
// Notification of child controller replacement
|
||||
- (void)revealController:(SWRevealViewController *)revealController willAddViewController:(UIViewController *)viewController
|
||||
forOperation:(SWRevealControllerOperation)operation animated:(BOOL)animated;
|
||||
- (void)revealController:(SWRevealViewController *)revealController didAddViewController:(UIViewController *)viewController
|
||||
forOperation:(SWRevealControllerOperation)operation animated:(BOOL)animated;
|
||||
|
||||
// Support for custom transition animations while replacing child controllers. If implemented, it will be fired in response
|
||||
// to calls to 'setXXViewController' methods
|
||||
- (id<UIViewControllerAnimatedTransitioning>)revealController:(SWRevealViewController *)revealController
|
||||
animationControllerForOperation:(SWRevealControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC;
|
||||
|
||||
// DEPRECATED - The following delegate methods will be removed some time in the future
|
||||
- (void)revealController:(SWRevealViewController *)revealController panGestureBeganFromLocation:(CGFloat)location progress:(CGFloat)progress; // (DEPRECATED)
|
||||
- (void)revealController:(SWRevealViewController *)revealController panGestureMovedToLocation:(CGFloat)location progress:(CGFloat)progress; // (DEPRECATED)
|
||||
- (void)revealController:(SWRevealViewController *)revealController panGestureEndedToLocation:(CGFloat)location progress:(CGFloat)progress; // (DEPRECATED)
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - UIViewController(SWRevealViewController) Category
|
||||
|
||||
// A category of UIViewController to let childViewControllers easily access their parent SWRevealViewController
|
||||
@interface UIViewController(SWRevealViewController)
|
||||
|
||||
- (SWRevealViewController*)revealViewController;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - StoryBoard support Classes
|
||||
|
||||
/* StoryBoard support */
|
||||
|
||||
// String identifiers to be applied to segues on a storyboard
|
||||
extern NSString* const SWSegueRearIdentifier; // this is @"sw_rear"
|
||||
extern NSString* const SWSegueFrontIdentifier; // this is @"sw_front"
|
||||
extern NSString* const SWSegueRightIdentifier; // this is @"sw_right"
|
||||
|
||||
/* This will allow the class to be defined on a storyboard */
|
||||
|
||||
// Use this along with one of the above segue identifiers to segue to the initial state
|
||||
@interface SWRevealViewControllerSegueSetController : UIStoryboardSegue
|
||||
@end
|
||||
|
||||
// Use this to push a view controller
|
||||
@interface SWRevealViewControllerSeguePushController : UIStoryboardSegue
|
||||
@end
|
||||
|
||||
|
||||
//#pragma mark - SWRevealViewControllerSegue (DEPRECATED)
|
||||
//
|
||||
//@interface SWRevealViewControllerSegue : UIStoryboardSegue // DEPRECATED: USE SWRevealViewControllerSegueSetController instead
|
||||
//@property (nonatomic, strong) void(^performBlock)( SWRevealViewControllerSegue* segue, UIViewController* svc, UIViewController* dvc );
|
||||
//@end
|
||||
+1897
@@ -0,0 +1,1897 @@
|
||||
/*
|
||||
|
||||
Copyright (c) 2013 Joan Lluch <[email protected]>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is furnished
|
||||
to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Early code inspired on a similar class by Philip Kluz ([email protected])
|
||||
|
||||
*/
|
||||
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
#import "SWRevealViewController.h"
|
||||
|
||||
|
||||
#pragma mark - StatusBar Helper Function
|
||||
|
||||
// computes the required offset adjustment due to the status bar for the passed in view,
|
||||
// it will return the statusBar height if view fully overlaps the statusBar, otherwise returns 0.0f
|
||||
static CGFloat statusBarAdjustment( UIView* view )
|
||||
{
|
||||
CGFloat adjustment = 0.0f;
|
||||
UIApplication *app = [UIApplication sharedApplication];
|
||||
CGRect viewFrame = [view convertRect:view.bounds toView:[app keyWindow]];
|
||||
CGRect statusBarFrame = [app statusBarFrame];
|
||||
|
||||
if ( CGRectIntersectsRect(viewFrame, statusBarFrame) )
|
||||
adjustment = fminf(statusBarFrame.size.width, statusBarFrame.size.height);
|
||||
|
||||
return adjustment;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - SWRevealView Class
|
||||
|
||||
@interface SWRevealView: UIView
|
||||
{
|
||||
__weak SWRevealViewController *_c;
|
||||
}
|
||||
|
||||
@property (nonatomic, readonly) UIView *rearView;
|
||||
@property (nonatomic, readonly) UIView *rightView;
|
||||
@property (nonatomic, readonly) UIView *frontView;
|
||||
@property (nonatomic, assign) BOOL disableLayout;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface SWRevealViewController()
|
||||
- (void)_getRevealWidth:(CGFloat*)pRevealWidth revealOverDraw:(CGFloat*)pRevealOverdraw forSymetry:(int)symetry;
|
||||
- (void)_getBounceBack:(BOOL*)pBounceBack pStableDrag:(BOOL*)pStableDrag forSymetry:(int)symetry;
|
||||
- (void)_getAdjustedFrontViewPosition:(FrontViewPosition*)frontViewPosition forSymetry:(int)symetry;
|
||||
@end
|
||||
|
||||
|
||||
@implementation SWRevealView
|
||||
|
||||
|
||||
static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1, CGFloat max1)
|
||||
{
|
||||
CGFloat result = min2 + (v1-min1)*((max2-min2)/(max1-min1));
|
||||
if ( result != result ) return min2; // nan
|
||||
if ( result < min2 ) return min2;
|
||||
if ( result > max2 ) return max2;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithFrame:(CGRect)frame controller:(SWRevealViewController*)controller
|
||||
{
|
||||
self = [super initWithFrame:frame];
|
||||
if ( self )
|
||||
{
|
||||
_c = controller;
|
||||
CGRect bounds = self.bounds;
|
||||
|
||||
_frontView = [[UIView alloc] initWithFrame:bounds];
|
||||
_frontView.autoresizingMask = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
|
||||
[self reloadShadow];
|
||||
|
||||
[self addSubview:_frontView];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)reloadShadow
|
||||
{
|
||||
CALayer *frontViewLayer = _frontView.layer;
|
||||
frontViewLayer.shadowColor = [_c.frontViewShadowColor CGColor];
|
||||
frontViewLayer.shadowOpacity = _c.frontViewShadowOpacity;
|
||||
frontViewLayer.shadowOffset = _c.frontViewShadowOffset;
|
||||
frontViewLayer.shadowRadius = _c.frontViewShadowRadius;
|
||||
}
|
||||
|
||||
|
||||
- (CGRect)hierarchycalFrameAdjustment:(CGRect)frame
|
||||
{
|
||||
if ( _c.presentFrontViewHierarchically )
|
||||
{
|
||||
UINavigationBar *dummyBar = [[UINavigationBar alloc] init];
|
||||
CGFloat barHeight = [dummyBar sizeThatFits:CGSizeMake(100,100)].height;
|
||||
CGFloat offset = barHeight + statusBarAdjustment(self);
|
||||
frame.origin.y += offset;
|
||||
frame.size.height -= offset;
|
||||
}
|
||||
return frame;
|
||||
}
|
||||
|
||||
|
||||
- (void)prepareRearViewForPosition:(FrontViewPosition)newPosition
|
||||
{
|
||||
if ( _rearView == nil )
|
||||
{
|
||||
_rearView = [[UIView alloc] initWithFrame:self.bounds];
|
||||
_rearView.autoresizingMask = /*UIViewAutoresizingFlexibleWidth|*/UIViewAutoresizingFlexibleHeight;
|
||||
[self insertSubview:_rearView belowSubview:_frontView];
|
||||
}
|
||||
|
||||
CGFloat xLocation = [self frontLocationForPosition:_c.frontViewPosition];
|
||||
[self _layoutRearViewsForLocation:xLocation];
|
||||
[self _prepareForNewPosition:newPosition];
|
||||
}
|
||||
|
||||
|
||||
- (void)prepareRightViewForPosition:(FrontViewPosition)newPosition
|
||||
{
|
||||
if ( _rightView == nil )
|
||||
{
|
||||
_rightView = [[UIView alloc] initWithFrame:self.bounds];
|
||||
_rightView.autoresizingMask = /*UIViewAutoresizingFlexibleWidth|*/UIViewAutoresizingFlexibleHeight;
|
||||
[self insertSubview:_rightView belowSubview:_frontView];
|
||||
}
|
||||
|
||||
CGFloat xLocation = [self frontLocationForPosition:_c.frontViewPosition];
|
||||
[self _layoutRearViewsForLocation:xLocation];
|
||||
[self _prepareForNewPosition:newPosition];
|
||||
}
|
||||
|
||||
|
||||
- (CGFloat)frontLocationForPosition:(FrontViewPosition)frontViewPosition
|
||||
{
|
||||
CGFloat revealWidth;
|
||||
CGFloat revealOverdraw;
|
||||
|
||||
CGFloat location = 0.0f;
|
||||
|
||||
int symetry = frontViewPosition<FrontViewPositionLeft? -1 : 1;
|
||||
[_c _getRevealWidth:&revealWidth revealOverDraw:&revealOverdraw forSymetry:symetry];
|
||||
[_c _getAdjustedFrontViewPosition:&frontViewPosition forSymetry:symetry];
|
||||
|
||||
if ( frontViewPosition == FrontViewPositionRight )
|
||||
location = revealWidth;
|
||||
|
||||
else if ( frontViewPosition > FrontViewPositionRight )
|
||||
location = revealWidth + revealOverdraw;
|
||||
|
||||
return location*symetry;
|
||||
}
|
||||
|
||||
|
||||
- (void)dragFrontViewToXLocation:(CGFloat)xLocation
|
||||
{
|
||||
CGRect bounds = self.bounds;
|
||||
|
||||
xLocation = [self _adjustedDragLocationForLocation:xLocation];
|
||||
[self _layoutRearViewsForLocation:xLocation];
|
||||
|
||||
CGRect frame = CGRectMake(xLocation, 0.0f, bounds.size.width, bounds.size.height);
|
||||
_frontView.frame = [self hierarchycalFrameAdjustment:frame];
|
||||
}
|
||||
|
||||
|
||||
# pragma mark - overrides
|
||||
|
||||
- (void)layoutSubviews
|
||||
{
|
||||
if ( _disableLayout ) return;
|
||||
|
||||
CGRect bounds = self.bounds;
|
||||
|
||||
FrontViewPosition position = _c.frontViewPosition;
|
||||
CGFloat xLocation = [self frontLocationForPosition:position];
|
||||
|
||||
// set rear view frames
|
||||
[self _layoutRearViewsForLocation:xLocation];
|
||||
|
||||
// set front view frame
|
||||
CGRect frame = CGRectMake(xLocation, 0.0f, bounds.size.width, bounds.size.height);
|
||||
_frontView.frame = [self hierarchycalFrameAdjustment:frame];
|
||||
|
||||
// setup front view shadow path if needed (front view loaded and not removed)
|
||||
UIViewController *frontViewController = _c.frontViewController;
|
||||
BOOL viewLoaded = frontViewController != nil && frontViewController.isViewLoaded;
|
||||
BOOL viewNotRemoved = position > FrontViewPositionLeftSideMostRemoved && position < FrontViewPositionRightMostRemoved;
|
||||
CGRect shadowBounds = viewLoaded && viewNotRemoved ? _frontView.bounds : CGRectZero;
|
||||
|
||||
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:shadowBounds];
|
||||
_frontView.layer.shadowPath = shadowPath.CGPath;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)pointInsideD:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
BOOL isInside = [super pointInside:point withEvent:event];
|
||||
if ( _c.extendsPointInsideHit )
|
||||
{
|
||||
if ( !isInside && _rearView && [_c.rearViewController isViewLoaded] )
|
||||
{
|
||||
CGPoint pt = [self convertPoint:point toView:_rearView];
|
||||
isInside = [_rearView pointInside:pt withEvent:event];
|
||||
}
|
||||
|
||||
if ( !isInside && _frontView && [_c.frontViewController isViewLoaded] )
|
||||
{
|
||||
CGPoint pt = [self convertPoint:point toView:_frontView];
|
||||
isInside = [_frontView pointInside:pt withEvent:event];
|
||||
}
|
||||
|
||||
if ( !isInside && _rightView && [_c.rightViewController isViewLoaded] )
|
||||
{
|
||||
CGPoint pt = [self convertPoint:point toView:_rightView];
|
||||
isInside = [_rightView pointInside:pt withEvent:event];
|
||||
}
|
||||
}
|
||||
return isInside;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
|
||||
{
|
||||
BOOL isInside = [super pointInside:point withEvent:event];
|
||||
if ( !isInside && _c.extendsPointInsideHit )
|
||||
{
|
||||
UIView *testViews[] = { _rearView, _frontView, _rightView };
|
||||
UIViewController *testControllers[] = { _c.rearViewController, _c.frontViewController, _c.rightViewController };
|
||||
|
||||
for ( NSInteger i=0 ; i<3 && !isInside ; i++ )
|
||||
{
|
||||
if ( testViews[i] && [testControllers[i] isViewLoaded] )
|
||||
{
|
||||
CGPoint pt = [self convertPoint:point toView:testViews[i]];
|
||||
isInside = [testViews[i] pointInside:pt withEvent:event];
|
||||
}
|
||||
}
|
||||
}
|
||||
return isInside;
|
||||
}
|
||||
|
||||
|
||||
# pragma mark - private
|
||||
|
||||
|
||||
- (void)_layoutRearViewsForLocation:(CGFloat)xLocation
|
||||
{
|
||||
CGRect bounds = self.bounds;
|
||||
|
||||
CGFloat rearRevealWidth = _c.rearViewRevealWidth;
|
||||
if ( rearRevealWidth < 0) rearRevealWidth = bounds.size.width + _c.rearViewRevealWidth;
|
||||
|
||||
CGFloat rearXLocation = scaledValue(xLocation, -_c.rearViewRevealDisplacement, 0, 0, rearRevealWidth);
|
||||
|
||||
CGFloat rearWidth = rearRevealWidth + _c.rearViewRevealOverdraw;
|
||||
_rearView.frame = CGRectMake(rearXLocation, 0.0, rearWidth, bounds.size.height);
|
||||
|
||||
CGFloat rightRevealWidth = _c.rightViewRevealWidth;
|
||||
if ( rightRevealWidth < 0) rightRevealWidth = bounds.size.width + _c.rightViewRevealWidth;
|
||||
|
||||
CGFloat rightXLocation = scaledValue(xLocation, 0, _c.rightViewRevealDisplacement, -rightRevealWidth, 0);
|
||||
|
||||
CGFloat rightWidth = rightRevealWidth + _c.rightViewRevealOverdraw;
|
||||
_rightView.frame = CGRectMake(bounds.size.width-rightWidth+rightXLocation, 0.0f, rightWidth, bounds.size.height);
|
||||
}
|
||||
|
||||
|
||||
- (void)_prepareForNewPosition:(FrontViewPosition)newPosition;
|
||||
{
|
||||
if ( _rearView == nil || _rightView == nil )
|
||||
return;
|
||||
|
||||
int symetry = newPosition<FrontViewPositionLeft? -1 : 1;
|
||||
|
||||
NSArray *subViews = self.subviews;
|
||||
NSInteger rearIndex = [subViews indexOfObjectIdenticalTo:_rearView];
|
||||
NSInteger rightIndex = [subViews indexOfObjectIdenticalTo:_rightView];
|
||||
|
||||
if ( (symetry < 0 && rightIndex < rearIndex) || (symetry > 0 && rearIndex < rightIndex) )
|
||||
[self exchangeSubviewAtIndex:rightIndex withSubviewAtIndex:rearIndex];
|
||||
}
|
||||
|
||||
|
||||
- (CGFloat)_adjustedDragLocationForLocation:(CGFloat)x
|
||||
{
|
||||
CGFloat result;
|
||||
|
||||
CGFloat revealWidth;
|
||||
CGFloat revealOverdraw;
|
||||
BOOL bounceBack;
|
||||
BOOL stableDrag;
|
||||
FrontViewPosition position = _c.frontViewPosition;
|
||||
|
||||
int symetry = x<0 ? -1 : 1;
|
||||
|
||||
[_c _getRevealWidth:&revealWidth revealOverDraw:&revealOverdraw forSymetry:symetry];
|
||||
[_c _getBounceBack:&bounceBack pStableDrag:&stableDrag forSymetry:symetry];
|
||||
|
||||
BOOL stableTrack = !bounceBack || stableDrag || position==FrontViewPositionRightMost || position==FrontViewPositionLeftSideMost;
|
||||
if ( stableTrack )
|
||||
{
|
||||
revealWidth += revealOverdraw;
|
||||
revealOverdraw = 0.0f;
|
||||
}
|
||||
|
||||
x = x * symetry;
|
||||
|
||||
if (x <= revealWidth)
|
||||
result = x; // Translate linearly.
|
||||
|
||||
else if (x <= revealWidth+2*revealOverdraw)
|
||||
result = revealWidth + (x-revealWidth)/2; // slow down translation by halph the movement.
|
||||
|
||||
else
|
||||
result = revealWidth+revealOverdraw; // keep at the rightMost location.
|
||||
|
||||
return result * symetry;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWContextTransitioningObject
|
||||
|
||||
@interface SWContextTransitionObject : NSObject<UIViewControllerContextTransitioning>
|
||||
@end
|
||||
|
||||
|
||||
@implementation SWContextTransitionObject
|
||||
{
|
||||
__weak SWRevealViewController *_revealVC;
|
||||
UIView *_view;
|
||||
UIViewController *_toVC;
|
||||
UIViewController *_fromVC;
|
||||
void (^_completion)(void);
|
||||
}
|
||||
|
||||
- (id)initWithRevealController:(SWRevealViewController*)revealVC containerView:(UIView*)view fromVC:(UIViewController*)fromVC
|
||||
toVC:(UIViewController*)toVC completion:(void (^)(void))completion
|
||||
{
|
||||
self = [super init];
|
||||
if ( self )
|
||||
{
|
||||
_revealVC = revealVC;
|
||||
_view = view;
|
||||
_fromVC = fromVC;
|
||||
_toVC = toVC;
|
||||
_completion = completion;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (UIView *)containerView
|
||||
{
|
||||
return _view;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isAnimated
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)isInteractive
|
||||
{
|
||||
return NO; // not supported
|
||||
}
|
||||
|
||||
- (BOOL)transitionWasCancelled
|
||||
{
|
||||
return NO; // not supported
|
||||
}
|
||||
|
||||
- (CGAffineTransform)targetTransform {
|
||||
return CGAffineTransformIdentity;
|
||||
}
|
||||
|
||||
- (UIModalPresentationStyle)presentationStyle
|
||||
{
|
||||
return UIModalPresentationNone; // not applicable
|
||||
}
|
||||
|
||||
|
||||
- (void)updateInteractiveTransition:(CGFloat)percentComplete
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
|
||||
- (void)finishInteractiveTransition
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
|
||||
- (void)cancelInteractiveTransition
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
|
||||
- (void)completeTransition:(BOOL)didComplete
|
||||
{
|
||||
_completion();
|
||||
}
|
||||
|
||||
|
||||
- (UIViewController *)viewControllerForKey:(NSString *)key
|
||||
{
|
||||
if ( [key isEqualToString:UITransitionContextFromViewControllerKey] )
|
||||
return _fromVC;
|
||||
|
||||
if ( [key isEqualToString:UITransitionContextToViewControllerKey] )
|
||||
return _toVC;
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (UIView *)viewForKey:(NSString *)key
|
||||
{
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (CGRect)initialFrameForViewController:(UIViewController *)vc
|
||||
{
|
||||
return _view.bounds;
|
||||
}
|
||||
|
||||
|
||||
- (CGRect)finalFrameForViewController:(UIViewController *)vc
|
||||
{
|
||||
return _view.bounds;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWDefaultAnimationController Class
|
||||
|
||||
@interface SWDefaultAnimationController : NSObject<UIViewControllerAnimatedTransitioning>
|
||||
@end
|
||||
|
||||
@implementation SWDefaultAnimationController
|
||||
{
|
||||
NSTimeInterval _duration;
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithDuration:(NSTimeInterval)duration
|
||||
{
|
||||
self = [super init];
|
||||
if ( self )
|
||||
{
|
||||
_duration = duration;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
|
||||
{
|
||||
return _duration;
|
||||
}
|
||||
|
||||
|
||||
- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext
|
||||
{
|
||||
UIViewController *fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
|
||||
UIViewController *toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
|
||||
|
||||
if ( fromViewController )
|
||||
{
|
||||
[UIView transitionFromView:fromViewController.view toView:toViewController.view duration:_duration
|
||||
options:UIViewAnimationOptionTransitionCrossDissolve|UIViewAnimationOptionOverrideInheritedOptions
|
||||
completion:^(BOOL finished) { [transitionContext completeTransition:finished]; }];
|
||||
}
|
||||
else
|
||||
{
|
||||
// tansitionFromView does not correctly handle the case where the fromView is nil (at least on iOS7) it just pops up the toView view with no animation,
|
||||
// so in such case we replace the crossDissolve animation by a simple alpha animation on the appearing view
|
||||
UIView *toView = toViewController.view;
|
||||
CGFloat alpha = toView.alpha;
|
||||
toView.alpha = 0;
|
||||
|
||||
[UIView animateWithDuration:_duration delay:0 options:UIViewAnimationOptionCurveEaseOut
|
||||
animations:^{ toView.alpha = alpha;}
|
||||
completion:^(BOOL finished) { [transitionContext completeTransition:finished];}];
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWRevealViewControllerPanGestureRecognizer
|
||||
|
||||
#import <UIKit/UIGestureRecognizerSubclass.h>
|
||||
|
||||
@interface SWRevealViewControllerPanGestureRecognizer : UIPanGestureRecognizer
|
||||
@end
|
||||
|
||||
@implementation SWRevealViewControllerPanGestureRecognizer
|
||||
{
|
||||
BOOL _dragging;
|
||||
CGPoint _beginPoint;
|
||||
}
|
||||
|
||||
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[super touchesBegan:touches withEvent:event];
|
||||
|
||||
UITouch *touch = [touches anyObject];
|
||||
_beginPoint = [touch locationInView:self.view];
|
||||
_dragging = NO;
|
||||
}
|
||||
|
||||
|
||||
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
[super touchesMoved:touches withEvent:event];
|
||||
|
||||
if ( _dragging || self.state == UIGestureRecognizerStateFailed)
|
||||
return;
|
||||
|
||||
const int kDirectionPanThreshold = 5;
|
||||
|
||||
UITouch *touch = [touches anyObject];
|
||||
CGPoint nowPoint = [touch locationInView:self.view];
|
||||
|
||||
if (abs(nowPoint.x - _beginPoint.x) > kDirectionPanThreshold) _dragging = YES;
|
||||
else if (abs(nowPoint.y - _beginPoint.y) > kDirectionPanThreshold) self.state = UIGestureRecognizerStateFailed;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWRevealViewController Class
|
||||
|
||||
@interface SWRevealViewController()<UIGestureRecognizerDelegate>
|
||||
{
|
||||
SWRevealView *_contentView;
|
||||
UIPanGestureRecognizer *_panGestureRecognizer;
|
||||
UITapGestureRecognizer *_tapGestureRecognizer;
|
||||
FrontViewPosition _frontViewPosition;
|
||||
FrontViewPosition _rearViewPosition;
|
||||
FrontViewPosition _rightViewPosition;
|
||||
SWContextTransitionObject *_rearTransitioningController;
|
||||
SWContextTransitionObject *_frontTransitioningController;
|
||||
SWContextTransitionObject *_rightTransitioningController;
|
||||
}
|
||||
@end
|
||||
|
||||
|
||||
@implementation SWRevealViewController
|
||||
{
|
||||
FrontViewPosition _panInitialFrontPosition;
|
||||
NSMutableArray *_animationQueue;
|
||||
BOOL _userInteractionStore;
|
||||
}
|
||||
|
||||
const int FrontViewPositionNone = 0xff;
|
||||
|
||||
|
||||
#pragma mark - Init
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)aDecoder
|
||||
{
|
||||
self = [super initWithCoder:aDecoder];
|
||||
if ( self )
|
||||
{
|
||||
[self _initDefaultProperties];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (id)init
|
||||
{
|
||||
return [self initWithRearViewController:nil frontViewController:nil];
|
||||
}
|
||||
|
||||
|
||||
- (id)initWithRearViewController:(UIViewController *)rearViewController frontViewController:(UIViewController *)frontViewController;
|
||||
{
|
||||
self = [super init];
|
||||
if ( self )
|
||||
{
|
||||
[self _initDefaultProperties];
|
||||
[self _performTransitionOperation:SWRevealControllerOperationReplaceRearController withViewController:rearViewController animated:NO];
|
||||
[self _performTransitionOperation:SWRevealControllerOperationReplaceFrontController withViewController:frontViewController animated:NO];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)_initDefaultProperties
|
||||
{
|
||||
_frontViewPosition = FrontViewPositionLeft;
|
||||
_rearViewPosition = FrontViewPositionLeft;
|
||||
_rightViewPosition = FrontViewPositionLeft;
|
||||
_rearViewRevealWidth = 260.0f;
|
||||
_rearViewRevealOverdraw = 60.0f;
|
||||
_rearViewRevealDisplacement = 40.0f;
|
||||
_rightViewRevealWidth = 260.0f;
|
||||
_rightViewRevealOverdraw = 60.0f;
|
||||
_rightViewRevealDisplacement = 40.0f;
|
||||
_bounceBackOnOverdraw = YES;
|
||||
_bounceBackOnLeftOverdraw = YES;
|
||||
_stableDragOnOverdraw = NO;
|
||||
_stableDragOnLeftOverdraw = NO;
|
||||
_presentFrontViewHierarchically = NO;
|
||||
_quickFlickVelocity = 250.0f;
|
||||
_toggleAnimationDuration = 0.3;
|
||||
_toggleAnimationType = SWRevealToggleAnimationTypeSpring;
|
||||
_springDampingRatio = 1;
|
||||
_replaceViewAnimationDuration = 0.25;
|
||||
_frontViewShadowRadius = 2.5f;
|
||||
_frontViewShadowOffset = CGSizeMake(0.0f, 2.5f);
|
||||
_frontViewShadowOpacity = 1.0f;
|
||||
_frontViewShadowColor = [UIColor blackColor];
|
||||
_userInteractionStore = YES;
|
||||
_animationQueue = [NSMutableArray array];
|
||||
_draggableBorderWidth = 0.0f;
|
||||
_clipsViewsToBounds = NO;
|
||||
_extendsPointInsideHit = NO;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - StatusBar
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarStyle
|
||||
{
|
||||
int positionDif = _frontViewPosition - FrontViewPositionLeft;
|
||||
|
||||
UIViewController *controller = _frontViewController;
|
||||
if ( positionDif > 0 ) controller = _rearViewController;
|
||||
else if ( positionDif < 0 ) controller = _rightViewController;
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
- (UIViewController *)childViewControllerForStatusBarHidden
|
||||
{
|
||||
UIViewController *controller = [self childViewControllerForStatusBarStyle];
|
||||
return controller;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - View lifecycle
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
// Do not call super, to prevent the apis from unfruitful looking for inexistent xibs!
|
||||
//[super loadView];
|
||||
|
||||
// load any defined front/rear controllers from the storyboard before
|
||||
[self loadStoryboardControllers];
|
||||
|
||||
// This is what Apple used to tell us to set as the initial frame, which is of course totally irrelevant
|
||||
// with view controller containment patterns, let's leave it for the sake of it!
|
||||
// CGRect frame = [[UIScreen mainScreen] applicationFrame];
|
||||
|
||||
// On iOS7 the applicationFrame does not return the whole screen. This is possibly a bug.
|
||||
// As a workaround we use the screen bounds, this still works on iOS6, any zero based frame would work anyway!
|
||||
CGRect frame = [[UIScreen mainScreen] bounds];
|
||||
|
||||
// create a custom content view for the controller
|
||||
_contentView = [[SWRevealView alloc] initWithFrame:frame controller:self];
|
||||
|
||||
// set the content view to resize along with its superview
|
||||
[_contentView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight];
|
||||
|
||||
// set the content view to clip its bounds if requested
|
||||
[_contentView setClipsToBounds:_clipsViewsToBounds];
|
||||
|
||||
// set our contentView to the controllers view
|
||||
self.view = _contentView;
|
||||
|
||||
// Apple also tells us to do this:
|
||||
_contentView.backgroundColor = [UIColor blackColor];
|
||||
|
||||
// we set the current frontViewPosition to none before seting the
|
||||
// desired initial position, this will force proper controller reload
|
||||
FrontViewPosition initialPosition = _frontViewPosition;
|
||||
_frontViewPosition = FrontViewPositionNone;
|
||||
_rearViewPosition = FrontViewPositionNone;
|
||||
_rightViewPosition = FrontViewPositionNone;
|
||||
|
||||
// now set the desired initial position
|
||||
[self _setFrontViewPosition:initialPosition withDuration:0.0];
|
||||
}
|
||||
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
|
||||
// Uncomment the following code if you want the child controllers
|
||||
// to be loaded at this point.
|
||||
//
|
||||
// We leave this commented out because we think loading childs here is conceptually wrong.
|
||||
// Instead, we refrain view loads until necesary, for example we may never load
|
||||
// the rear controller view -or the front controller view- if it is never displayed.
|
||||
//
|
||||
// If you need to manipulate views of any of your child controllers in an override
|
||||
// of this method, you can load yourself the views explicitly on your overriden method.
|
||||
// However we discourage it as an app following the MVC principles should never need to do so
|
||||
|
||||
// [_frontViewController view];
|
||||
// [_rearViewController view];
|
||||
|
||||
// we store at this point the view's user interaction state as we may temporarily disable it
|
||||
// and resume it back to the previous state, it is possible to override this behaviour by
|
||||
// intercepting it on the panGestureBegan and panGestureEnded delegates
|
||||
_userInteractionStore = _contentView.userInteractionEnabled;
|
||||
}
|
||||
|
||||
|
||||
- (NSUInteger)supportedInterfaceOrientations
|
||||
{
|
||||
// we could have simply not implemented this, but we choose to call super to make explicit that we
|
||||
// want the default behavior.
|
||||
return [super supportedInterfaceOrientations];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Public methods and property accessors
|
||||
|
||||
- (void)setFrontViewController:(UIViewController *)frontViewController
|
||||
{
|
||||
[self setFrontViewController:frontViewController animated:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewController:(UIViewController *)frontViewController animated:(BOOL)animated
|
||||
{
|
||||
if ( ![self isViewLoaded])
|
||||
{
|
||||
[self _performTransitionOperation:SWRevealControllerOperationReplaceFrontController withViewController:frontViewController animated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
[self _dispatchTransitionOperation:SWRevealControllerOperationReplaceFrontController withViewController:frontViewController animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)pushFrontViewController:(UIViewController *)frontViewController animated:(BOOL)animated
|
||||
{
|
||||
if ( ![self isViewLoaded])
|
||||
{
|
||||
[self _performTransitionOperation:SWRevealControllerOperationReplaceFrontController withViewController:frontViewController animated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
[self _dispatchPushFrontViewController:frontViewController animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)setRearViewController:(UIViewController *)rearViewController
|
||||
{
|
||||
[self setRearViewController:rearViewController animated:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void)setRearViewController:(UIViewController *)rearViewController animated:(BOOL)animated
|
||||
{
|
||||
if ( ![self isViewLoaded])
|
||||
{
|
||||
[self _performTransitionOperation:SWRevealControllerOperationReplaceRearController withViewController:rearViewController animated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
[self _dispatchTransitionOperation:SWRevealControllerOperationReplaceRearController withViewController:rearViewController animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)setRightViewController:(UIViewController *)rightViewController
|
||||
{
|
||||
[self setRightViewController:rightViewController animated:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void)setRightViewController:(UIViewController *)rightViewController animated:(BOOL)animated
|
||||
{
|
||||
if ( ![self isViewLoaded])
|
||||
{
|
||||
[self _performTransitionOperation:SWRevealControllerOperationReplaceRightController withViewController:rightViewController animated:NO];
|
||||
return;
|
||||
}
|
||||
|
||||
[self _dispatchTransitionOperation:SWRevealControllerOperationReplaceRightController withViewController:rightViewController animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)revealToggleAnimated:(BOOL)animated
|
||||
{
|
||||
FrontViewPosition toggledFrontViewPosition = FrontViewPositionLeft;
|
||||
if (_frontViewPosition <= FrontViewPositionLeft)
|
||||
toggledFrontViewPosition = FrontViewPositionRight;
|
||||
|
||||
[self setFrontViewPosition:toggledFrontViewPosition animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)rightRevealToggleAnimated:(BOOL)animated
|
||||
{
|
||||
FrontViewPosition toggledFrontViewPosition = FrontViewPositionLeft;
|
||||
if (_frontViewPosition >= FrontViewPositionLeft)
|
||||
toggledFrontViewPosition = FrontViewPositionLeftSide;
|
||||
|
||||
[self setFrontViewPosition:toggledFrontViewPosition animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewPosition:(FrontViewPosition)frontViewPosition
|
||||
{
|
||||
[self setFrontViewPosition:frontViewPosition animated:NO];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewPosition:(FrontViewPosition)frontViewPosition animated:(BOOL)animated
|
||||
{
|
||||
if ( ![self isViewLoaded] )
|
||||
{
|
||||
_frontViewPosition = frontViewPosition;
|
||||
_rearViewPosition = frontViewPosition;
|
||||
_rightViewPosition = frontViewPosition;
|
||||
return;
|
||||
}
|
||||
|
||||
[self _dispatchSetFrontViewPosition:frontViewPosition animated:animated];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewShadowRadius:(CGFloat)frontViewShadowRadius
|
||||
{
|
||||
_frontViewShadowRadius = frontViewShadowRadius;
|
||||
[_contentView reloadShadow];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewShadowOffset:(CGSize)frontViewShadowOffset
|
||||
{
|
||||
_frontViewShadowOffset = frontViewShadowOffset;
|
||||
[_contentView reloadShadow];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewShadowOpacity:(CGFloat)frontViewShadowOpacity
|
||||
{
|
||||
_frontViewShadowOpacity = frontViewShadowOpacity;
|
||||
[_contentView reloadShadow];
|
||||
}
|
||||
|
||||
|
||||
- (void)setFrontViewShadowColor:(UIColor *)frontViewShadowColor
|
||||
{
|
||||
_frontViewShadowColor = frontViewShadowColor;
|
||||
[_contentView reloadShadow];
|
||||
}
|
||||
|
||||
|
||||
- (UIPanGestureRecognizer*)panGestureRecognizer
|
||||
{
|
||||
if ( _panGestureRecognizer == nil )
|
||||
{
|
||||
_panGestureRecognizer = [[SWRevealViewControllerPanGestureRecognizer alloc] initWithTarget:self action:@selector(_handleRevealGesture:)];
|
||||
_panGestureRecognizer.delegate = self;
|
||||
[_contentView.frontView addGestureRecognizer:_panGestureRecognizer];
|
||||
}
|
||||
return _panGestureRecognizer;
|
||||
}
|
||||
|
||||
|
||||
- (UITapGestureRecognizer*)tapGestureRecognizer
|
||||
{
|
||||
if ( _tapGestureRecognizer == nil )
|
||||
{
|
||||
UITapGestureRecognizer *tapRecognizer =
|
||||
[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(_handleTapGesture:)];
|
||||
|
||||
tapRecognizer.delegate = self;
|
||||
[_contentView.frontView addGestureRecognizer:tapRecognizer];
|
||||
_tapGestureRecognizer = tapRecognizer ;
|
||||
}
|
||||
return _tapGestureRecognizer;
|
||||
}
|
||||
|
||||
|
||||
- (void)setClipsViewsToBounds:(BOOL)clipsViewsToBounds
|
||||
{
|
||||
_clipsViewsToBounds = clipsViewsToBounds;
|
||||
[_contentView setClipsToBounds:clipsViewsToBounds];
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark - Provided acction methods
|
||||
|
||||
- (IBAction)revealToggle:(id)sender
|
||||
{
|
||||
[self revealToggleAnimated:YES];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)rightRevealToggle:(id)sender
|
||||
{
|
||||
[self rightRevealToggleAnimated:YES];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - UserInteractionEnabling
|
||||
|
||||
// disable userInteraction on the entire control
|
||||
- (void)_disableUserInteraction
|
||||
{
|
||||
[_contentView setUserInteractionEnabled:NO];
|
||||
[_contentView setDisableLayout:YES];
|
||||
}
|
||||
|
||||
// restore userInteraction on the control
|
||||
- (void)_restoreUserInteraction
|
||||
{
|
||||
// we use the stored userInteraction state just in case a developer decided
|
||||
// to have our view interaction disabled beforehand
|
||||
[_contentView setUserInteractionEnabled:_userInteractionStore];
|
||||
[_contentView setDisableLayout:NO];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - PanGesture progress notification
|
||||
|
||||
- (void)_notifyPanGestureBegan
|
||||
{
|
||||
if ( [_delegate respondsToSelector:@selector(revealControllerPanGestureBegan:)] )
|
||||
[_delegate revealControllerPanGestureBegan:self];
|
||||
|
||||
CGFloat xLocation, dragProgress, overProgress;
|
||||
[self _getDragLocation:&xLocation progress:&dragProgress overdrawProgress:&overProgress];
|
||||
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:panGestureBeganFromLocation:progress:overProgress:)] )
|
||||
[_delegate revealController:self panGestureBeganFromLocation:xLocation progress:dragProgress overProgress:overProgress];
|
||||
|
||||
else if ( [_delegate respondsToSelector:@selector(revealController:panGestureBeganFromLocation:progress:)] )
|
||||
[_delegate revealController:self panGestureBeganFromLocation:xLocation progress:dragProgress];
|
||||
}
|
||||
|
||||
- (void)_notifyPanGestureMoved
|
||||
{
|
||||
CGFloat xLocation, dragProgress, overProgress;
|
||||
[self _getDragLocation:&xLocation progress:&dragProgress overdrawProgress:&overProgress];
|
||||
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:panGestureMovedToLocation:progress:overProgress:)] )
|
||||
[_delegate revealController:self panGestureMovedToLocation:xLocation progress:dragProgress overProgress:overProgress];
|
||||
|
||||
else if ( [_delegate respondsToSelector:@selector(revealController:panGestureMovedToLocation:progress:)] )
|
||||
[_delegate revealController:self panGestureMovedToLocation:xLocation progress:dragProgress];
|
||||
}
|
||||
|
||||
- (void)_notifyPanGestureEnded
|
||||
{
|
||||
CGFloat xLocation, dragProgress, overProgress;
|
||||
[self _getDragLocation:&xLocation progress:&dragProgress overdrawProgress:&overProgress];
|
||||
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:panGestureEndedToLocation:progress:overProgress:)] )
|
||||
[_delegate revealController:self panGestureEndedToLocation:xLocation progress:dragProgress overProgress:overProgress];
|
||||
|
||||
else if ( [_delegate respondsToSelector:@selector(revealController:panGestureEndedToLocation:progress:)] )
|
||||
[_delegate revealController:self panGestureEndedToLocation:xLocation progress:dragProgress];
|
||||
|
||||
if ( [_delegate respondsToSelector:@selector(revealControllerPanGestureEnded:)] )
|
||||
[_delegate revealControllerPanGestureEnded:self];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Symetry
|
||||
|
||||
- (void)_getRevealWidth:(CGFloat*)pRevealWidth revealOverDraw:(CGFloat*)pRevealOverdraw forSymetry:(int)symetry
|
||||
{
|
||||
if ( symetry < 0 ) *pRevealWidth = _rightViewRevealWidth, *pRevealOverdraw = _rightViewRevealOverdraw;
|
||||
else *pRevealWidth = _rearViewRevealWidth, *pRevealOverdraw = _rearViewRevealOverdraw;
|
||||
|
||||
if (*pRevealWidth < 0) *pRevealWidth = _contentView.bounds.size.width + *pRevealWidth;
|
||||
}
|
||||
|
||||
- (void)_getBounceBack:(BOOL*)pBounceBack pStableDrag:(BOOL*)pStableDrag forSymetry:(int)symetry
|
||||
{
|
||||
if ( symetry < 0 ) *pBounceBack = _bounceBackOnLeftOverdraw, *pStableDrag = _stableDragOnLeftOverdraw;
|
||||
else *pBounceBack = _bounceBackOnOverdraw, *pStableDrag = _stableDragOnOverdraw;
|
||||
}
|
||||
|
||||
- (void)_getAdjustedFrontViewPosition:(FrontViewPosition*)frontViewPosition forSymetry:(int)symetry
|
||||
{
|
||||
if ( symetry < 0 ) *frontViewPosition = FrontViewPositionLeft + symetry*(*frontViewPosition-FrontViewPositionLeft);
|
||||
}
|
||||
|
||||
- (void)_getDragLocationx:(CGFloat*)xLocation progress:(CGFloat*)progress
|
||||
{
|
||||
UIView *frontView = _contentView.frontView;
|
||||
*xLocation = frontView.frame.origin.x;
|
||||
|
||||
int symetry = *xLocation<0 ? -1 : 1;
|
||||
|
||||
CGFloat xWidth = symetry < 0 ? _rightViewRevealWidth : _rearViewRevealWidth;
|
||||
if ( xWidth < 0 ) xWidth = _contentView.bounds.size.width + xWidth;
|
||||
|
||||
*progress = *xLocation/xWidth * symetry;
|
||||
}
|
||||
|
||||
- (void)_getDragLocation:(CGFloat*)xLocation progress:(CGFloat*)progress overdrawProgress:(CGFloat*)overProgress
|
||||
{
|
||||
UIView *frontView = _contentView.frontView;
|
||||
*xLocation = frontView.frame.origin.x;
|
||||
|
||||
int symetry = *xLocation<0 ? -1 : 1;
|
||||
|
||||
CGFloat xWidth = symetry < 0 ? _rightViewRevealWidth : _rearViewRevealWidth;
|
||||
CGFloat xOverWidth = symetry < 0 ? _rightViewRevealOverdraw : _rearViewRevealOverdraw;
|
||||
|
||||
if ( xWidth < 0 ) xWidth = _contentView.bounds.size.width + xWidth;
|
||||
|
||||
*progress = *xLocation*symetry/xWidth;
|
||||
*overProgress = (*xLocation*symetry-xWidth)/xOverWidth;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Deferred block execution queue
|
||||
|
||||
// Define a convenience macro to enqueue single statements
|
||||
#define _enqueue(code) [self _enqueueBlock:^{code;}];
|
||||
|
||||
// Defers the execution of the passed in block until a paired _dequeue call is received,
|
||||
// or executes the block right away if no pending requests are present.
|
||||
- (void)_enqueueBlock:(void (^)(void))block
|
||||
{
|
||||
[_animationQueue insertObject:block atIndex:0];
|
||||
if ( _animationQueue.count == 1)
|
||||
{
|
||||
block();
|
||||
}
|
||||
}
|
||||
|
||||
// Removes the top most block in the queue and executes the following one if any.
|
||||
// Calls to this method must be paired with calls to _enqueueBlock, particularly it may be called
|
||||
// from within a block passed to _enqueueBlock to remove itself when done with animations.
|
||||
- (void)_dequeue
|
||||
{
|
||||
[_animationQueue removeLastObject];
|
||||
|
||||
if ( _animationQueue.count > 0 )
|
||||
{
|
||||
void (^block)(void) = [_animationQueue lastObject];
|
||||
block();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Gesture Delegate
|
||||
|
||||
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)recognizer
|
||||
{
|
||||
// only allow gesture if no previous request is in process
|
||||
if ( _animationQueue.count == 0 )
|
||||
{
|
||||
if ( recognizer == _panGestureRecognizer )
|
||||
return [self _panGestureShouldBegin];
|
||||
|
||||
if ( recognizer == _tapGestureRecognizer )
|
||||
return [self _tapGestureShouldBegin];
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
|
||||
{
|
||||
if ( gestureRecognizer == _panGestureRecognizer )
|
||||
{
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:panGestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:)] )
|
||||
if ( [_delegate revealController:self panGestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer] != NO )
|
||||
return YES;
|
||||
}
|
||||
if ( gestureRecognizer == _tapGestureRecognizer )
|
||||
{
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:tapGestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:)] )
|
||||
if ( [_delegate revealController:self tapGestureRecognizerShouldRecognizeSimultaneouslyWithGestureRecognizer:otherGestureRecognizer] != NO )
|
||||
return YES;
|
||||
}
|
||||
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)_tapGestureShouldBegin
|
||||
{
|
||||
if ( _frontViewPosition == FrontViewPositionLeft ||
|
||||
_frontViewPosition == FrontViewPositionRightMostRemoved ||
|
||||
_frontViewPosition == FrontViewPositionLeftSideMostRemoved )
|
||||
return NO;
|
||||
|
||||
// forbid gesture if the following delegate is implemented and returns NO
|
||||
if ( [_delegate respondsToSelector:@selector(revealControllerTapGestureShouldBegin:)] )
|
||||
if ( [_delegate revealControllerTapGestureShouldBegin:self] == NO )
|
||||
return NO;
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)_panGestureShouldBegin
|
||||
{
|
||||
// forbid gesture if the initial translation is not horizontal
|
||||
UIView *recognizerView = _panGestureRecognizer.view;
|
||||
CGPoint translation = [_panGestureRecognizer translationInView:recognizerView];
|
||||
// NSLog( @"translation:%@", NSStringFromCGPoint(translation) );
|
||||
// if ( fabs(translation.y/translation.x) > 1 )
|
||||
// return NO;
|
||||
|
||||
// forbid gesture if the following delegate is implemented and returns NO
|
||||
if ( [_delegate respondsToSelector:@selector(revealControllerPanGestureShouldBegin:)] )
|
||||
if ( [_delegate revealControllerPanGestureShouldBegin:self] == NO )
|
||||
return NO;
|
||||
|
||||
CGFloat xLocation = [_panGestureRecognizer locationInView:recognizerView].x;
|
||||
CGFloat width = recognizerView.bounds.size.width;
|
||||
|
||||
BOOL draggableBorderAllowing = (
|
||||
/*_frontViewPosition != FrontViewPositionLeft ||*/ _draggableBorderWidth == 0.0f ||
|
||||
(_rearViewController && xLocation <= _draggableBorderWidth) ||
|
||||
(_rightViewController && xLocation >= (width - _draggableBorderWidth)) );
|
||||
|
||||
|
||||
BOOL translationForbidding = ( _frontViewPosition == FrontViewPositionLeft &&
|
||||
((_rearViewController == nil && translation.x > 0) || (_rightViewController == nil && translation.x < 0)) );
|
||||
|
||||
// allow gesture only within the bounds defined by the draggableBorderWidth property
|
||||
return draggableBorderAllowing && !translationForbidding ;
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Gesture Based Reveal
|
||||
|
||||
- (void)_handleTapGesture:(UITapGestureRecognizer *)recognizer
|
||||
{
|
||||
NSTimeInterval duration = _toggleAnimationDuration;
|
||||
[self _setFrontViewPosition:FrontViewPositionLeft withDuration:duration];
|
||||
}
|
||||
|
||||
|
||||
- (void)_handleRevealGesture:(UIPanGestureRecognizer *)recognizer
|
||||
{
|
||||
switch ( recognizer.state )
|
||||
{
|
||||
case UIGestureRecognizerStateBegan:
|
||||
[self _handleRevealGestureStateBeganWithRecognizer:recognizer];
|
||||
break;
|
||||
|
||||
case UIGestureRecognizerStateChanged:
|
||||
[self _handleRevealGestureStateChangedWithRecognizer:recognizer];
|
||||
break;
|
||||
|
||||
case UIGestureRecognizerStateEnded:
|
||||
[self _handleRevealGestureStateEndedWithRecognizer:recognizer];
|
||||
break;
|
||||
|
||||
case UIGestureRecognizerStateCancelled:
|
||||
//case UIGestureRecognizerStateFailed:
|
||||
[self _handleRevealGestureStateCancelledWithRecognizer:recognizer];
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)_handleRevealGestureStateBeganWithRecognizer:(UIPanGestureRecognizer *)recognizer
|
||||
{
|
||||
// we know that we will not get here unless the animationQueue is empty because the recognizer
|
||||
// delegate prevents it, however we do not want any forthcoming programatic actions to disturb
|
||||
// the gesture, so we just enqueue a dummy block to ensure any programatic acctions will be
|
||||
// scheduled after the gesture is completed
|
||||
[self _enqueueBlock:^{}]; // <-- dummy block
|
||||
|
||||
// we store the initial position and initialize a target position
|
||||
_panInitialFrontPosition = _frontViewPosition;
|
||||
|
||||
// we disable user interactions on the views, however programatic accions will still be
|
||||
// enqueued to be performed after the gesture completes
|
||||
[self _disableUserInteraction];
|
||||
[self _notifyPanGestureBegan];
|
||||
}
|
||||
|
||||
|
||||
- (void)_handleRevealGestureStateChangedWithRecognizer:(UIPanGestureRecognizer *)recognizer
|
||||
{
|
||||
CGFloat translation = [recognizer translationInView:_contentView].x;
|
||||
|
||||
CGFloat baseLocation = [_contentView frontLocationForPosition:_panInitialFrontPosition];
|
||||
CGFloat xLocation = baseLocation + translation;
|
||||
|
||||
if ( xLocation < 0 )
|
||||
{
|
||||
if ( _rightViewController == nil ) xLocation = 0;
|
||||
[self _rightViewDeploymentForNewFrontViewPosition:FrontViewPositionLeftSide]();
|
||||
[self _rearViewDeploymentForNewFrontViewPosition:FrontViewPositionLeftSide]();
|
||||
}
|
||||
|
||||
if ( xLocation > 0 )
|
||||
{
|
||||
if ( _rearViewController == nil ) xLocation = 0;
|
||||
[self _rightViewDeploymentForNewFrontViewPosition:FrontViewPositionRight]();
|
||||
[self _rearViewDeploymentForNewFrontViewPosition:FrontViewPositionRight]();
|
||||
}
|
||||
|
||||
[_contentView dragFrontViewToXLocation:xLocation];
|
||||
[self _notifyPanGestureMoved];
|
||||
}
|
||||
|
||||
|
||||
- (void)_handleRevealGestureStateEndedWithRecognizer:(UIPanGestureRecognizer *)recognizer
|
||||
{
|
||||
UIView *frontView = _contentView.frontView;
|
||||
|
||||
CGFloat xLocation = frontView.frame.origin.x;
|
||||
CGFloat velocity = [recognizer velocityInView:_contentView].x;
|
||||
//NSLog( @"Velocity:%1.4f", velocity);
|
||||
|
||||
// depending on position we compute a simetric replacement of widths and positions
|
||||
int symetry = xLocation<0 ? -1 : 1;
|
||||
|
||||
// simetring computing of widths
|
||||
CGFloat revealWidth ;
|
||||
CGFloat revealOverdraw ;
|
||||
BOOL bounceBack;
|
||||
BOOL stableDrag;
|
||||
|
||||
[self _getRevealWidth:&revealWidth revealOverDraw:&revealOverdraw forSymetry:symetry];
|
||||
[self _getBounceBack:&bounceBack pStableDrag:&stableDrag forSymetry:symetry];
|
||||
|
||||
// simetric replacement of position
|
||||
xLocation = xLocation * symetry;
|
||||
|
||||
// initially we assume drag to left and default duration
|
||||
FrontViewPosition frontViewPosition = FrontViewPositionLeft;
|
||||
NSTimeInterval duration = _toggleAnimationDuration;
|
||||
|
||||
// Velocity driven change:
|
||||
if (fabsf(velocity) > _quickFlickVelocity)
|
||||
{
|
||||
// we may need to set the drag position and to adjust the animation duration
|
||||
CGFloat journey = xLocation;
|
||||
if (velocity*symetry > 0.0f)
|
||||
{
|
||||
frontViewPosition = FrontViewPositionRight;
|
||||
journey = revealWidth - xLocation;
|
||||
if (xLocation > revealWidth)
|
||||
{
|
||||
if (!bounceBack && stableDrag /*&& xPosition > _rearViewRevealWidth+_rearViewRevealOverdraw*0.5f*/)
|
||||
{
|
||||
frontViewPosition = FrontViewPositionRightMost;
|
||||
journey = revealWidth+revealOverdraw - xLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
duration = fabsf(journey/velocity);
|
||||
}
|
||||
|
||||
// Position driven change:
|
||||
else
|
||||
{
|
||||
// we may need to set the drag position
|
||||
if (xLocation > revealWidth*0.5f)
|
||||
{
|
||||
frontViewPosition = FrontViewPositionRight;
|
||||
if (xLocation > revealWidth)
|
||||
{
|
||||
if (bounceBack)
|
||||
frontViewPosition = FrontViewPositionLeft;
|
||||
|
||||
else if (stableDrag && xLocation > revealWidth+revealOverdraw*0.5f)
|
||||
frontViewPosition = FrontViewPositionRightMost;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// symetric replacement of frontViewPosition
|
||||
[self _getAdjustedFrontViewPosition:&frontViewPosition forSymetry:symetry];
|
||||
|
||||
// restore user interaction and animate to the final position
|
||||
[self _restoreUserInteraction];
|
||||
[self _notifyPanGestureEnded];
|
||||
[self _setFrontViewPosition:frontViewPosition withDuration:duration];
|
||||
}
|
||||
|
||||
|
||||
- (void)_handleRevealGestureStateCancelledWithRecognizer:(UIPanGestureRecognizer *)recognizer
|
||||
{
|
||||
[self _restoreUserInteraction];
|
||||
[self _notifyPanGestureEnded];
|
||||
[self _dequeue];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Enqueued position and controller setup
|
||||
|
||||
- (void)_dispatchSetFrontViewPosition:(FrontViewPosition)frontViewPosition animated:(BOOL)animated
|
||||
{
|
||||
NSTimeInterval duration = animated?_toggleAnimationDuration:0.0;
|
||||
__weak SWRevealViewController *theSelf = self;
|
||||
_enqueue( [theSelf _setFrontViewPosition:frontViewPosition withDuration:duration] );
|
||||
}
|
||||
|
||||
|
||||
- (void)_dispatchPushFrontViewController:(UIViewController *)newFrontViewController animated:(BOOL)animated
|
||||
{
|
||||
FrontViewPosition preReplacementPosition = FrontViewPositionLeft;
|
||||
if ( _frontViewPosition > FrontViewPositionLeft ) preReplacementPosition = FrontViewPositionRightMost;
|
||||
if ( _frontViewPosition < FrontViewPositionLeft ) preReplacementPosition = FrontViewPositionLeftSideMost;
|
||||
|
||||
NSTimeInterval duration = animated?_toggleAnimationDuration:0.0;
|
||||
NSTimeInterval firstDuration = duration;
|
||||
int initialPosDif = abs( _frontViewPosition - preReplacementPosition );
|
||||
if ( initialPosDif == 1 ) firstDuration *= 0.8;
|
||||
else if ( initialPosDif == 0 ) firstDuration = 0;
|
||||
|
||||
__weak SWRevealViewController *theSelf = self;
|
||||
if ( animated )
|
||||
{
|
||||
_enqueue( [theSelf _setFrontViewPosition:preReplacementPosition withDuration:firstDuration] );
|
||||
_enqueue( [theSelf _performTransitionOperation:SWRevealControllerOperationReplaceFrontController withViewController:newFrontViewController animated:NO] );
|
||||
_enqueue( [theSelf _setFrontViewPosition:FrontViewPositionLeft withDuration:duration] );
|
||||
}
|
||||
else
|
||||
{
|
||||
_enqueue( [theSelf _performTransitionOperation:SWRevealControllerOperationReplaceFrontController withViewController:newFrontViewController animated:NO] );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)_dispatchTransitionOperation:(SWRevealControllerOperation)operation withViewController:(UIViewController *)newViewController animated:(BOOL)animated
|
||||
{
|
||||
__weak SWRevealViewController *theSelf = self;
|
||||
_enqueue( [theSelf _performTransitionOperation:operation withViewController:newViewController animated:animated] );
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Animated view controller deployment and layout
|
||||
|
||||
// Primitive method for view controller deployment and animated layout to the given position.
|
||||
- (void)_setFrontViewPosition:(FrontViewPosition)newPosition withDuration:(NSTimeInterval)duration
|
||||
{
|
||||
void (^rearDeploymentCompletion)() = [self _rearViewDeploymentForNewFrontViewPosition:newPosition];
|
||||
void (^rightDeploymentCompletion)() = [self _rightViewDeploymentForNewFrontViewPosition:newPosition];
|
||||
void (^frontDeploymentCompletion)() = [self _frontViewDeploymentForNewFrontViewPosition:newPosition];
|
||||
|
||||
void (^animations)() = ^()
|
||||
{
|
||||
// Calling this in the animation block causes the status bar to appear/dissapear in sync with our own animation
|
||||
[self setNeedsStatusBarAppearanceUpdate];
|
||||
|
||||
// We call the layoutSubviews method on the contentView view and send a delegate, which will
|
||||
// occur inside of an animation block if any animated transition is being performed
|
||||
[_contentView layoutSubviews];
|
||||
|
||||
if ([_delegate respondsToSelector:@selector(revealController:animateToPosition:)])
|
||||
[_delegate revealController:self animateToPosition:_frontViewPosition];
|
||||
};
|
||||
|
||||
void (^completion)(BOOL) = ^(BOOL finished)
|
||||
{
|
||||
rearDeploymentCompletion();
|
||||
rightDeploymentCompletion();
|
||||
frontDeploymentCompletion();
|
||||
[self _dequeue];
|
||||
};
|
||||
|
||||
if ( duration > 0.0 )
|
||||
{
|
||||
if ( _toggleAnimationType == SWRevealToggleAnimationTypeEaseOut )
|
||||
{
|
||||
[UIView animateWithDuration:duration delay:0.0
|
||||
options:UIViewAnimationOptionCurveEaseOut animations:animations completion:completion];
|
||||
}
|
||||
else
|
||||
{
|
||||
[UIView animateWithDuration:_toggleAnimationDuration delay:0.0 usingSpringWithDamping:_springDampingRatio initialSpringVelocity:1/duration
|
||||
options:0 animations:animations completion:completion];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
animations();
|
||||
completion(YES);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Primitive method for animated controller transition
|
||||
//- (void)_performTransitionToViewController:(UIViewController*)new operation:(SWRevealControllerOperation)operation animated:(BOOL)animated
|
||||
- (void)_performTransitionOperation:(SWRevealControllerOperation)operation withViewController:(UIViewController*)new animated:(BOOL)animated
|
||||
{
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:willAddViewController:forOperation:animated:)] )
|
||||
[_delegate revealController:self willAddViewController:new forOperation:operation animated:animated];
|
||||
|
||||
UIViewController *old = nil;
|
||||
UIView *view = nil;
|
||||
|
||||
if ( operation == SWRevealControllerOperationReplaceRearController )
|
||||
old = _rearViewController, _rearViewController = new, view = _contentView.rearView;
|
||||
|
||||
else if ( operation == SWRevealControllerOperationReplaceFrontController )
|
||||
old = _frontViewController, _frontViewController = new, view = _contentView.frontView;
|
||||
|
||||
else if ( operation == SWRevealControllerOperationReplaceRightController )
|
||||
old = _rightViewController, _rightViewController = new, view = _contentView.rightView;
|
||||
|
||||
void (^completion)() = [self _transitionFromViewController:old toViewController:new inView:view];
|
||||
|
||||
void (^animationCompletion)() = ^
|
||||
{
|
||||
completion();
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:didAddViewController:forOperation:animated:)] )
|
||||
[_delegate revealController:self didAddViewController:new forOperation:operation animated:animated];
|
||||
|
||||
[self _dequeue];
|
||||
};
|
||||
|
||||
if ( animated )
|
||||
{
|
||||
id<UIViewControllerAnimatedTransitioning> animationController = nil;
|
||||
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:animationControllerForOperation:fromViewController:toViewController:)] )
|
||||
animationController = [_delegate revealController:self animationControllerForOperation:operation fromViewController:old toViewController:new];
|
||||
|
||||
if ( !animationController )
|
||||
animationController = [[SWDefaultAnimationController alloc] initWithDuration:_replaceViewAnimationDuration];
|
||||
|
||||
SWContextTransitionObject *transitioningObject = [[SWContextTransitionObject alloc] initWithRevealController:self containerView:view
|
||||
fromVC:old toVC:new completion:animationCompletion];
|
||||
|
||||
if ( [animationController transitionDuration:transitioningObject] > 0 )
|
||||
[animationController animateTransition:transitioningObject];
|
||||
else
|
||||
animationCompletion();
|
||||
}
|
||||
else
|
||||
{
|
||||
animationCompletion();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Position based view controller deployment
|
||||
|
||||
// Deploy/Undeploy of the front view controller following the containment principles. Returns a block
|
||||
// that must be invoked on animation completion in order to finish deployment
|
||||
- (void (^)(void))_frontViewDeploymentForNewFrontViewPosition:(FrontViewPosition)newPosition
|
||||
{
|
||||
if ( (_rightViewController == nil && newPosition < FrontViewPositionLeft) ||
|
||||
(_rearViewController == nil && newPosition > FrontViewPositionLeft) )
|
||||
newPosition = FrontViewPositionLeft;
|
||||
|
||||
BOOL positionIsChanging = (_frontViewPosition != newPosition);
|
||||
|
||||
BOOL appear =
|
||||
(_frontViewPosition >= FrontViewPositionRightMostRemoved || _frontViewPosition <= FrontViewPositionLeftSideMostRemoved || _frontViewPosition == FrontViewPositionNone) &&
|
||||
(newPosition < FrontViewPositionRightMostRemoved && newPosition > FrontViewPositionLeftSideMostRemoved);
|
||||
|
||||
BOOL disappear =
|
||||
(newPosition >= FrontViewPositionRightMostRemoved || newPosition <= FrontViewPositionLeftSideMostRemoved ) &&
|
||||
(_frontViewPosition < FrontViewPositionRightMostRemoved && _frontViewPosition > FrontViewPositionLeftSideMostRemoved && _frontViewPosition != FrontViewPositionNone);
|
||||
|
||||
if ( positionIsChanging )
|
||||
{
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:willMoveToPosition:)] )
|
||||
[_delegate revealController:self willMoveToPosition:newPosition];
|
||||
}
|
||||
|
||||
_frontViewPosition = newPosition;
|
||||
|
||||
void (^deploymentCompletion)() =
|
||||
[self _deploymentForViewController:_frontViewController inView:_contentView.frontView appear:appear disappear:disappear];
|
||||
|
||||
void (^completion)() = ^()
|
||||
{
|
||||
deploymentCompletion();
|
||||
if ( positionIsChanging )
|
||||
{
|
||||
if ( [_delegate respondsToSelector:@selector(revealController:didMoveToPosition:)] )
|
||||
[_delegate revealController:self didMoveToPosition:newPosition];
|
||||
}
|
||||
};
|
||||
|
||||
return completion;
|
||||
}
|
||||
|
||||
// Deploy/Undeploy of the left view controller following the containment principles. Returns a block
|
||||
// that must be invoked on animation completion in order to finish deployment
|
||||
- (void (^)(void))_rearViewDeploymentForNewFrontViewPosition:(FrontViewPosition)newPosition
|
||||
{
|
||||
if ( _presentFrontViewHierarchically )
|
||||
newPosition = FrontViewPositionRight;
|
||||
|
||||
if ( _rearViewController == nil && newPosition > FrontViewPositionLeft )
|
||||
newPosition = FrontViewPositionLeft;
|
||||
|
||||
BOOL appear = (_rearViewPosition <= FrontViewPositionLeft || _rearViewPosition == FrontViewPositionNone) && newPosition > FrontViewPositionLeft;
|
||||
BOOL disappear = newPosition <= FrontViewPositionLeft && (_rearViewPosition > FrontViewPositionLeft && _rearViewPosition != FrontViewPositionNone);
|
||||
|
||||
if ( appear )
|
||||
[_contentView prepareRearViewForPosition:newPosition];
|
||||
|
||||
_rearViewPosition = newPosition;
|
||||
|
||||
return [self _deploymentForViewController:_rearViewController inView:_contentView.rearView appear:appear disappear:disappear];
|
||||
}
|
||||
|
||||
// Deploy/Undeploy of the right view controller following the containment principles. Returns a block
|
||||
// that must be invoked on animation completion in order to finish deployment
|
||||
- (void (^)(void))_rightViewDeploymentForNewFrontViewPosition:(FrontViewPosition)newPosition
|
||||
{
|
||||
if ( _rightViewController == nil && newPosition < FrontViewPositionLeft )
|
||||
newPosition = FrontViewPositionLeft;
|
||||
|
||||
BOOL appear = (_rightViewPosition >= FrontViewPositionLeft || _rightViewPosition == FrontViewPositionNone) && newPosition < FrontViewPositionLeft ;
|
||||
BOOL disappear = newPosition >= FrontViewPositionLeft && (_rightViewPosition < FrontViewPositionLeft && _rightViewPosition != FrontViewPositionNone);
|
||||
|
||||
if ( appear )
|
||||
[_contentView prepareRightViewForPosition:newPosition];
|
||||
|
||||
_rightViewPosition = newPosition;
|
||||
|
||||
return [self _deploymentForViewController:_rightViewController inView:_contentView.rightView appear:appear disappear:disappear];
|
||||
}
|
||||
|
||||
|
||||
- (void (^)(void)) _deploymentForViewController:(UIViewController*)controller inView:(UIView*)view appear:(BOOL)appear disappear:(BOOL)disappear
|
||||
{
|
||||
if ( appear ) return [self _deployForViewController:controller inView:view];
|
||||
if ( disappear ) return [self _undeployForViewController:controller];
|
||||
return ^{};
|
||||
}
|
||||
|
||||
|
||||
#pragma mark Containment view controller deployment and transition
|
||||
|
||||
// Containment Deploy method. Returns a block to be invoked at the
|
||||
// animation completion, or right after return in case of non-animated deployment.
|
||||
- (void (^)(void))_deployForViewController:(UIViewController*)controller inView:(UIView*)view
|
||||
{
|
||||
if ( !controller || !view )
|
||||
return ^(void){};
|
||||
|
||||
CGRect frame = view.bounds;
|
||||
|
||||
UIView *controllerView = controller.view;
|
||||
controllerView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
|
||||
controllerView.frame = frame;
|
||||
|
||||
if ( [controllerView isKindOfClass:[UIScrollView class]] )
|
||||
{
|
||||
BOOL adjust = controller.automaticallyAdjustsScrollViewInsets;
|
||||
|
||||
if ( adjust )
|
||||
{
|
||||
[(id)controllerView setContentInset:UIEdgeInsetsMake(statusBarAdjustment(_contentView), 0, 0, 0)];
|
||||
}
|
||||
}
|
||||
|
||||
[view addSubview:controllerView];
|
||||
|
||||
void (^completionBlock)(void) = ^(void)
|
||||
{
|
||||
// nothing to do on completion at this stage
|
||||
};
|
||||
|
||||
return completionBlock;
|
||||
}
|
||||
|
||||
// Containment Undeploy method. Returns a block to be invoked at the
|
||||
// animation completion, or right after return in case of non-animated deployment.
|
||||
- (void (^)(void))_undeployForViewController:(UIViewController*)controller
|
||||
{
|
||||
if (!controller)
|
||||
return ^(void){};
|
||||
|
||||
// nothing to do before completion at this stage
|
||||
|
||||
void (^completionBlock)(void) = ^(void)
|
||||
{
|
||||
[controller.view removeFromSuperview];
|
||||
};
|
||||
|
||||
return completionBlock;
|
||||
}
|
||||
|
||||
// Containment Transition method. Returns a block to be invoked at the
|
||||
// animation completion, or right after return in case of non-animated transition.
|
||||
- (void(^)(void))_transitionFromViewController:(UIViewController*)fromController toViewController:(UIViewController*)toController inView:(UIView*)view
|
||||
{
|
||||
if ( fromController == toController )
|
||||
return ^(void){};
|
||||
|
||||
if ( toController ) [self addChildViewController:toController];
|
||||
|
||||
void (^deployCompletion)() = [self _deployForViewController:toController inView:view];
|
||||
|
||||
[fromController willMoveToParentViewController:nil];
|
||||
|
||||
void (^undeployCompletion)() = [self _undeployForViewController:fromController];
|
||||
|
||||
void (^completionBlock)(void) = ^(void)
|
||||
{
|
||||
undeployCompletion() ;
|
||||
[fromController removeFromParentViewController];
|
||||
|
||||
deployCompletion() ;
|
||||
[toController didMoveToParentViewController:self];
|
||||
};
|
||||
return completionBlock;
|
||||
}
|
||||
|
||||
// Load any defined front/rear controllers from the storyboard
|
||||
// This method is intended to be overrided in case the default behavior will not meet your needs
|
||||
- (void)loadStoryboardControllers
|
||||
{
|
||||
if ( self.storyboard && _rearViewController == nil )
|
||||
{
|
||||
//Try each segue separately so it doesn't break prematurely if either Rear or Right views are not used.
|
||||
@try
|
||||
{
|
||||
[self performSegueWithIdentifier:SWSegueRearIdentifier sender:nil];
|
||||
}
|
||||
@catch(NSException *exception) {}
|
||||
|
||||
@try
|
||||
{
|
||||
[self performSegueWithIdentifier:SWSegueFrontIdentifier sender:nil];
|
||||
}
|
||||
@catch(NSException *exception) {}
|
||||
|
||||
@try
|
||||
{
|
||||
[self performSegueWithIdentifier:SWSegueRightIdentifier sender:nil];
|
||||
}
|
||||
@catch(NSException *exception) {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark state preservation / restoration
|
||||
|
||||
+ (UIViewController *)viewControllerWithRestorationIdentifierPath:(NSArray *)identifierComponents coder:(NSCoder*)coder
|
||||
{
|
||||
SWRevealViewController* vc = nil;
|
||||
UIStoryboard* sb = [coder decodeObjectForKey:UIStateRestorationViewControllerStoryboardKey];
|
||||
|
||||
if (sb)
|
||||
{
|
||||
vc = (SWRevealViewController*)[sb instantiateViewControllerWithIdentifier:@"SWRevealViewController"];
|
||||
vc.restorationIdentifier = [identifierComponents lastObject];
|
||||
vc.restorationClass = [SWRevealViewController class];
|
||||
}
|
||||
return vc;
|
||||
}
|
||||
|
||||
|
||||
- (void)encodeRestorableStateWithCoder:(NSCoder *)coder
|
||||
{
|
||||
[coder encodeDouble:_rearViewRevealWidth forKey:@"_rearViewRevealWidth"];
|
||||
[coder encodeDouble:_rearViewRevealOverdraw forKey:@"_rearViewRevealOverdraw"];
|
||||
[coder encodeDouble:_rearViewRevealDisplacement forKey:@"_rearViewRevealDisplacement"];
|
||||
[coder encodeDouble:_rightViewRevealWidth forKey:@"_rightViewRevealWidth"];
|
||||
[coder encodeDouble:_rightViewRevealOverdraw forKey:@"_rightViewRevealOverdraw"];
|
||||
[coder encodeDouble:_rightViewRevealDisplacement forKey:@"_rightViewRevealDisplacement"];
|
||||
[coder encodeBool:_bounceBackOnOverdraw forKey:@"_bounceBackOnOverdraw"];
|
||||
[coder encodeBool:_bounceBackOnLeftOverdraw forKey:@"_bounceBackOnLeftOverdraw"];
|
||||
[coder encodeBool:_stableDragOnOverdraw forKey:@"_stableDragOnOverdraw"];
|
||||
[coder encodeBool:_stableDragOnLeftOverdraw forKey:@"_stableDragOnLeftOverdraw"];
|
||||
[coder encodeBool:_presentFrontViewHierarchically forKey:@"_presentFrontViewHierarchically"];
|
||||
[coder encodeDouble:_quickFlickVelocity forKey:@"_quickFlickVelocity"];
|
||||
[coder encodeDouble:_toggleAnimationDuration forKey:@"_toggleAnimationDuration"];
|
||||
[coder encodeInteger:_toggleAnimationType forKey:@"_toggleAnimationType"];
|
||||
[coder encodeDouble:_springDampingRatio forKey:@"_springDampingRatio"];
|
||||
[coder encodeDouble:_replaceViewAnimationDuration forKey:@"_replaceViewAnimationDuration"];
|
||||
[coder encodeDouble:_frontViewShadowRadius forKey:@"_frontViewShadowRadius"];
|
||||
[coder encodeCGSize:_frontViewShadowOffset forKey:@"_frontViewShadowOffset"];
|
||||
[coder encodeDouble:_frontViewShadowOpacity forKey:@"_frontViewShadowOpacity"];
|
||||
[coder encodeObject:_frontViewShadowColor forKey:@"_frontViewShadowColor"];
|
||||
[coder encodeBool:_userInteractionStore forKey:@"_userInteractionStore"];
|
||||
[coder encodeDouble:_draggableBorderWidth forKey:@"_draggableBorderWidth"];
|
||||
[coder encodeBool:_clipsViewsToBounds forKey:@"_clipsViewsToBounds"];
|
||||
[coder encodeBool:_extendsPointInsideHit forKey:@"_extendsPointInsideHit"];
|
||||
|
||||
[coder encodeObject:_rearViewController forKey:@"_rearViewController"];
|
||||
[coder encodeObject:_frontViewController forKey:@"_frontViewController"];
|
||||
[coder encodeObject:_rightViewController forKey:@"_rightViewController"];
|
||||
|
||||
[coder encodeInteger:_frontViewPosition forKey:@"_frontViewPosition"];
|
||||
|
||||
[super encodeRestorableStateWithCoder:coder];
|
||||
}
|
||||
|
||||
|
||||
- (void)decodeRestorableStateWithCoder:(NSCoder *)coder
|
||||
{
|
||||
_rearViewRevealWidth = [coder decodeDoubleForKey:@"_rearViewRevealWidth"];
|
||||
_rearViewRevealOverdraw = [coder decodeDoubleForKey:@"_rearViewRevealOverdraw"];
|
||||
_rearViewRevealDisplacement = [coder decodeDoubleForKey:@"_rearViewRevealDisplacement"];
|
||||
_rightViewRevealWidth = [coder decodeDoubleForKey:@"_rightViewRevealWidth"];
|
||||
_rightViewRevealOverdraw = [coder decodeDoubleForKey:@"_rightViewRevealOverdraw"];
|
||||
_rightViewRevealDisplacement = [coder decodeDoubleForKey:@"_rightViewRevealDisplacement"];
|
||||
_bounceBackOnOverdraw = [coder decodeBoolForKey:@"_bounceBackOnOverdraw"];
|
||||
_bounceBackOnLeftOverdraw = [coder decodeBoolForKey:@"_bounceBackOnLeftOverdraw"];
|
||||
_stableDragOnOverdraw = [coder decodeBoolForKey:@"_stableDragOnOverdraw"];
|
||||
_stableDragOnLeftOverdraw = [coder decodeBoolForKey:@"_stableDragOnLeftOverdraw"];
|
||||
_presentFrontViewHierarchically = [coder decodeBoolForKey:@"_presentFrontViewHierarchically"];
|
||||
_quickFlickVelocity = [coder decodeDoubleForKey:@"_quickFlickVelocity"];
|
||||
_toggleAnimationDuration = [coder decodeDoubleForKey:@"_toggleAnimationDuration"];
|
||||
_toggleAnimationType = [coder decodeIntegerForKey:@"_toggleAnimationType"];
|
||||
_springDampingRatio = [coder decodeDoubleForKey:@"_springDampingRatio"];
|
||||
_replaceViewAnimationDuration = [coder decodeDoubleForKey:@"_replaceViewAnimationDuration"];
|
||||
_frontViewShadowRadius = [coder decodeDoubleForKey:@"_frontViewShadowRadius"];
|
||||
_frontViewShadowOffset = [coder decodeCGSizeForKey:@"_frontViewShadowOffset"];
|
||||
_frontViewShadowOpacity = [coder decodeDoubleForKey:@"_frontViewShadowOpacity"];
|
||||
_frontViewShadowColor = [coder decodeObjectForKey:@"_frontViewShadowColor"];
|
||||
_userInteractionStore = [coder decodeBoolForKey:@"_userInteractionStore"];
|
||||
_animationQueue = [NSMutableArray array];
|
||||
_draggableBorderWidth = [coder decodeDoubleForKey:@"_draggableBorderWidth"];
|
||||
_clipsViewsToBounds = [coder decodeBoolForKey:@"_clipsViewsToBounds"];
|
||||
_extendsPointInsideHit = [coder decodeBoolForKey:@"_extendsPointInsideHit"];
|
||||
|
||||
[self setRearViewController:[coder decodeObjectForKey:@"_rearViewController"]];
|
||||
[self setFrontViewController:[coder decodeObjectForKey:@"_frontViewController"]];
|
||||
[self setRightViewController:[coder decodeObjectForKey:@"_rightViewController"]];
|
||||
|
||||
[self setFrontViewPosition:[coder decodeIntForKey: @"_frontViewPosition"]];
|
||||
|
||||
[super decodeRestorableStateWithCoder:coder];
|
||||
}
|
||||
|
||||
|
||||
- (void)applicationFinishedRestoringState
|
||||
{
|
||||
// nothing to do at this stage
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - UIViewController(SWRevealViewController) Category
|
||||
|
||||
@implementation UIViewController(SWRevealViewController)
|
||||
|
||||
- (SWRevealViewController*)revealViewController
|
||||
{
|
||||
UIViewController *parent = self;
|
||||
Class revealClass = [SWRevealViewController class];
|
||||
while ( nil != (parent = [parent parentViewController]) && ![parent isKindOfClass:revealClass] ) {}
|
||||
return (id)parent;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWRevealViewControllerSegueSetController segue identifiers
|
||||
|
||||
NSString * const SWSegueRearIdentifier = @"sw_rear";
|
||||
NSString * const SWSegueFrontIdentifier = @"sw_front";
|
||||
NSString * const SWSegueRightIdentifier = @"sw_right";
|
||||
|
||||
|
||||
#pragma mark - SWRevealViewControllerSegueSetController class
|
||||
|
||||
@implementation SWRevealViewControllerSegueSetController
|
||||
|
||||
- (void)perform
|
||||
{
|
||||
SWRevealControllerOperation operation = SWRevealControllerOperationNone;
|
||||
|
||||
NSString *identifier = self.identifier;
|
||||
SWRevealViewController *rvc = self.sourceViewController;
|
||||
UIViewController *dvc = self.destinationViewController;
|
||||
|
||||
if ( [identifier isEqualToString:SWSegueFrontIdentifier] )
|
||||
operation = SWRevealControllerOperationReplaceFrontController;
|
||||
|
||||
else if ( [identifier isEqualToString:SWSegueRearIdentifier] )
|
||||
operation = SWRevealControllerOperationReplaceRearController;
|
||||
|
||||
else if ( [identifier isEqualToString:SWSegueRightIdentifier] )
|
||||
operation = SWRevealControllerOperationReplaceRightController;
|
||||
|
||||
if ( operation != SWRevealControllerOperationNone )
|
||||
[rvc _performTransitionOperation:operation withViewController:dvc animated:NO];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#pragma mark - SWRevealViewControllerSeguePushController class
|
||||
|
||||
@implementation SWRevealViewControllerSeguePushController
|
||||
|
||||
- (void)perform
|
||||
{
|
||||
SWRevealViewController *rvc = [self.sourceViewController revealViewController];
|
||||
UIViewController *dvc = self.destinationViewController;
|
||||
[rvc pushFrontViewController:dvc animated:YES];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//#pragma mark - SWRevealViewControllerSegue Class
|
||||
//
|
||||
//@implementation SWRevealViewControllerSegue // DEPRECATED
|
||||
//
|
||||
//- (void)perform
|
||||
//{
|
||||
// if ( _performBlock )
|
||||
// _performBlock( self, self.sourceViewController, self.destinationViewController );
|
||||
//}
|
||||
//
|
||||
//@end
|
||||
//
|
||||
//
|
||||
//#pragma mark Storyboard support
|
||||
//
|
||||
//@implementation SWRevealViewController(deprecated)
|
||||
//
|
||||
//- (void)prepareForSegue:(SWRevealViewControllerSegue *)segue sender:(id)sender // TO REMOVE: DEPRECATED IMPLEMENTATION
|
||||
//{
|
||||
// // This method is required for compatibility with SWRevealViewControllerSegue, now deprecated.
|
||||
// // It can be simply removed when using SWRevealViewControllerSegueSetController and SWRevealViewControlerSeguePushController
|
||||
//
|
||||
// NSString *identifier = segue.identifier;
|
||||
// if ( [segue isKindOfClass:[SWRevealViewControllerSegue class]] && sender == nil )
|
||||
// {
|
||||
// if ( [identifier isEqualToString:SWSegueRearIdentifier] )
|
||||
// {
|
||||
// segue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc)
|
||||
// {
|
||||
// [self _setRearViewController:dvc animated:NO];
|
||||
// };
|
||||
// }
|
||||
// else if ( [identifier isEqualToString:SWSegueFrontIdentifier] )
|
||||
// {
|
||||
// segue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc)
|
||||
// {
|
||||
// [self _setFrontViewController:dvc animated:NO];
|
||||
// };
|
||||
// }
|
||||
// else if ( [identifier isEqualToString:SWSegueRightIdentifier] )
|
||||
// {
|
||||
// segue.performBlock = ^(SWRevealViewControllerSegue* rvc_segue, UIViewController* svc, UIViewController* dvc)
|
||||
// {
|
||||
// [self _setRightViewController:dvc animated:NO];
|
||||
// };
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
//
|
||||
//@end
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// SettingsViewController.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/27/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "AppDelegate.h"
|
||||
|
||||
@interface SettingsViewController : UIViewController
|
||||
@property (strong, nonatomic) IBOutlet UILabel *bitrateLabel;
|
||||
@property (strong, nonatomic) IBOutlet UISlider *bitrateSlider;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *framerateSelector;
|
||||
@property (strong, nonatomic) IBOutlet UISegmentedControl *resolutionSelector;
|
||||
|
||||
- (void) saveSettings;
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,64 @@
|
||||
//
|
||||
// SettingsViewController.m
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/27/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SettingsViewController.h"
|
||||
#import "Settings.h"
|
||||
#import "DataManager.h"
|
||||
|
||||
#define BITRATE_INTERVAL 100
|
||||
|
||||
@implementation SettingsViewController {
|
||||
NSInteger _bitrate;
|
||||
}
|
||||
static NSString* bitrateFormat = @"Bitrate: %d bps";
|
||||
|
||||
|
||||
- (void)viewDidLoad {
|
||||
[super viewDidLoad];
|
||||
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
Settings* currentSettings = [dataMan retrieveSettings];
|
||||
|
||||
_bitrate = [currentSettings.bitrate integerValue];
|
||||
NSInteger framerate = [currentSettings.framerate integerValue] == 30 ? 0 : 1;
|
||||
NSInteger resolution = [currentSettings.height integerValue] == 720 ? 0 : 1;
|
||||
|
||||
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
||||
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
||||
[self.bitrateSlider setValue:_bitrate animated:YES];
|
||||
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, (int)_bitrate]];
|
||||
}
|
||||
|
||||
- (void) bitrateSliderMoved {
|
||||
_bitrate = BITRATE_INTERVAL * floor((self.bitrateSlider.value/BITRATE_INTERVAL)+0.5);
|
||||
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, (int)_bitrate]];
|
||||
}
|
||||
|
||||
|
||||
- (void) saveSettings {
|
||||
DataManager* dataMan = [[DataManager alloc] init];
|
||||
NSInteger framerate = [self.framerateSelector selectedSegmentIndex] == 0 ? 30 : 60;
|
||||
NSInteger height = [self.resolutionSelector selectedSegmentIndex] == 0 ? 720 : 1080;
|
||||
NSInteger width = height == 720 ? 1280 : 1920;
|
||||
[dataMan saveSettingsWithBitrate:_bitrate framerate:framerate height:height width:width];
|
||||
}
|
||||
|
||||
- (void)didReceiveMemoryWarning {
|
||||
[super didReceiveMemoryWarning];
|
||||
// Dispose of any resources that can be recreated.
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Navigation
|
||||
|
||||
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
@@ -25,6 +25,8 @@
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
[self.navigationController setNavigationBarHidden:YES animated:YES];
|
||||
|
||||
[self.stageLabel setText:@"Starting App"];
|
||||
[self.stageLabel sizeToFit];
|
||||
self.stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self.stageLabel.center.y);
|
||||
@@ -45,9 +47,13 @@
|
||||
object:nil];
|
||||
}
|
||||
|
||||
- (void) returnToMainFrame {
|
||||
[self.navigationController popToRootViewControllerAnimated:YES];
|
||||
}
|
||||
|
||||
- (void)applicationWillResignActive:(NSNotification *)notification {
|
||||
[_streamMan stopStream];
|
||||
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||
[self returnToMainFrame];
|
||||
}
|
||||
|
||||
- (void) connectionStarted {
|
||||
@@ -65,7 +71,7 @@
|
||||
|
||||
UIAlertController* conTermAlert = [UIAlertController alertControllerWithTitle:@"Connection Terminated" message:@"The connection terminated unexpectedly" preferredStyle:UIAlertControllerStyleAlert];
|
||||
[conTermAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||
[self returnToMainFrame];
|
||||
}]];
|
||||
[self presentViewController:conTermAlert animated:YES completion:nil];
|
||||
|
||||
@@ -92,7 +98,7 @@
|
||||
stageName, errorCode]
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||
[self returnToMainFrame];
|
||||
}]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
@@ -102,7 +108,7 @@
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||
[self performSegueWithIdentifier:@"returnToMainFrame" sender:self];
|
||||
[self returnToMainFrame];
|
||||
}]];
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
@@ -11,10 +11,20 @@
|
||||
<view key="view" contentMode="scaleToFill" id="Icf-Kt-Ai7">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="xFJ-oz-Sim">
|
||||
<rect key="frame" x="16" y="20" width="34" height="34"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<state key="normal" backgroundImage="Settings">
|
||||
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</state>
|
||||
</button>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<connections>
|
||||
<outlet property="settingsButton" destination="xFJ-oz-Sim" id="SqR-wJ-2Gg"/>
|
||||
<segue destination="OIm-0n-i9v" kind="modal" identifier="createStreamFrame" modalPresentationStyle="fullScreen" id="MOD-9A-3Sk"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
@@ -60,6 +70,9 @@
|
||||
<point key="canvasLocation" x="1252" y="-312"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Settings" width="37" height="37"/>
|
||||
</resources>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
<simulatedStatusBarMetrics key="statusBar" statusBarStyle="lightContent"/>
|
||||
<simulatedOrientationMetrics key="orientation"/>
|
||||
|
||||
+114
-6
@@ -1,10 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6250" systemVersion="14A388a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="dgh-JZ-Q7z">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6250" systemVersion="14A388a" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--Main Frame View Controller-->
|
||||
<!--Limelight-->
|
||||
<scene sceneID="emz-kO-L7q">
|
||||
<objects>
|
||||
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
@@ -14,15 +14,119 @@
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<toolbarItems/>
|
||||
<navigationItem key="navigationItem" title="Limelight" id="1jn-Sf-Xky">
|
||||
<barButtonItem key="leftBarButtonItem" image="Settings" id="5gr-O1-slj"/>
|
||||
</navigationItem>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<connections>
|
||||
<segue destination="mI3-9F-XwU" kind="modal" identifier="createStreamFrame" id="cPc-eP-un1"/>
|
||||
<outlet property="settingsSidebarButton" destination="5gr-O1-slj" id="vK6-bY-5h5"/>
|
||||
<segue destination="mI3-9F-XwU" kind="push" identifier="createStreamFrame" id="Vgc-B6-lvM"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="HNf-lX-GEO" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="199" y="7"/>
|
||||
<point key="canvasLocation" x="1363" y="796"/>
|
||||
</scene>
|
||||
<!--Reveal View Controller-->
|
||||
<scene sceneID="QYt-XN-Ojr">
|
||||
<objects>
|
||||
<viewController id="DL0-L5-LOv" customClass="SWRevealViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="Usg-e0-g4a">
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<connections>
|
||||
<segue destination="rYd-e6-cQU" kind="custom" identifier="sw_rear" customClass="SWRevealViewControllerSegueSetController" id="vBQ-bn-yZu"/>
|
||||
<segue destination="ftZ-kC-fxI" kind="custom" identifier="sw_front" customClass="SWRevealViewControllerSegueSetController" id="V3E-d5-bsZ"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="RXm-iV-Zqb" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="-64" y="804"/>
|
||||
</scene>
|
||||
<!--Side Bar-->
|
||||
<scene sceneID="uYM-56-Ivb">
|
||||
<objects>
|
||||
<viewController id="rYd-e6-cQU" userLabel="Side Bar" customClass="SettingsViewController" sceneMemberID="viewController">
|
||||
<view key="view" contentMode="scaleToFill" id="iNk-qF-gIr" customClass="UIScrollView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
<subviews>
|
||||
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="10000" minValue="0.0" maxValue="50000" id="3nn-MI-9Xu">
|
||||
<rect key="frame" x="14" y="72" width="204" height="31"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</slider>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10000 bps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="SBv-Wn-LB7">
|
||||
<rect key="frame" x="17" y="43" width="142" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="dLF-qJ-2nY">
|
||||
<rect key="frame" x="16" y="156" width="123" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="30 Hz"/>
|
||||
<segment title="60 Hz"/>
|
||||
</segments>
|
||||
</segmentedControl>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Kkv-DF-MAl">
|
||||
<rect key="frame" x="16" y="127" width="83" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="8zy-ri-Dqc">
|
||||
<rect key="frame" x="16" y="206" width="82" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="PCM-t4-Sha">
|
||||
<rect key="frame" x="16" y="235" width="123" height="29"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<segments>
|
||||
<segment title="720p"/>
|
||||
<segment title="1080p"/>
|
||||
</segments>
|
||||
</segmentedControl>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<connections>
|
||||
<outlet property="bitrateLabel" destination="SBv-Wn-LB7" id="Wdu-me-Bvd"/>
|
||||
<outlet property="bitrateSlider" destination="3nn-MI-9Xu" id="IuD-Rk-vPp"/>
|
||||
<outlet property="framerateSelector" destination="dLF-qJ-2nY" id="hE3-hk-iwa"/>
|
||||
<outlet property="resolutionSelector" destination="PCM-t4-Sha" id="t60-W2-wkV"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="RWc-Km-KG5" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="1363" y="1266"/>
|
||||
</scene>
|
||||
<!--Navigation Controller-->
|
||||
<scene sceneID="pfX-8A-htT">
|
||||
<objects>
|
||||
<navigationController id="ftZ-kC-fxI" sceneMemberID="viewController">
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<navigationBar key="navigationBar" contentMode="scaleToFill" id="0ZA-Ec-QgD">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
</navigationBar>
|
||||
<connections>
|
||||
<segue destination="dgh-JZ-Q7z" kind="relationship" relationship="rootViewController" id="NhF-R8-8s3"/>
|
||||
</connections>
|
||||
</navigationController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Dr2-S8-dHh" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="660" y="796"/>
|
||||
</scene>
|
||||
<!--Stream Frame View Controller-->
|
||||
<scene sceneID="5Eb-q2-vjt">
|
||||
@@ -46,20 +150,24 @@
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<navigationItem key="navigationItem" id="8uX-4T-BiC"/>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
<nil key="simulatedBottomBarMetrics"/>
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
<connections>
|
||||
<outlet property="spinner" destination="0vm-Iv-K4b" id="Lif-zG-6Jh"/>
|
||||
<outlet property="stageLabel" destination="2HK-Z5-4Ch" id="1bI-Ig-OpD"/>
|
||||
<segue destination="dgh-JZ-Q7z" kind="modal" identifier="returnToMainFrame" id="djB-MF-L5D"/>
|
||||
</connections>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="pqv-jd-33O" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="930" y="-14"/>
|
||||
<point key="canvasLocation" x="2092" y="796"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
<resources>
|
||||
<image name="Settings" width="17" height="17"/>
|
||||
</resources>
|
||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
||||
<simulatedStatusBarMetrics key="statusBar"/>
|
||||
<simulatedOrientationMetrics key="orientation"/>
|
||||
|
||||
Reference in New Issue
Block a user