new ui is almost fully functional
- add hosts - pair to host - get app list - launch app - resume app
@@ -47,6 +47,7 @@
|
||||
FB8946EB19F6AFE100339C8A /* libcrypto.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB8946E019F6AFB800339C8A /* libcrypto.a */; };
|
||||
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 */; };
|
||||
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 */; };
|
||||
@@ -214,12 +215,14 @@
|
||||
FB8946E719F6AFB800339C8A /* opus_multistream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_multistream.h; sourceTree = "<group>"; };
|
||||
FB8946E819F6AFB800339C8A /* opus_types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = opus_types.h; sourceTree = "<group>"; };
|
||||
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>"; };
|
||||
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>"; };
|
||||
FBDE86E519F82297001C18A8 /* UIAppView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAppView.m; sourceTree = "<group>"; };
|
||||
FBDE86E719F82315001C18A8 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = App.h; sourceTree = "<group>"; };
|
||||
FBDE86E819F82315001C18A8 /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = App.m; sourceTree = "<group>"; };
|
||||
FBDE86E719F82315001C18A8 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = ../App.h; sourceTree = "<group>"; };
|
||||
FBDE86E819F82315001C18A8 /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = App.m; path = ../App.m; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@@ -320,8 +323,6 @@
|
||||
FBDE86DF19F7A837001C18A8 /* UIComputerView.m */,
|
||||
FBDE86E419F82297001C18A8 /* UIAppView.h */,
|
||||
FBDE86E519F82297001C18A8 /* UIAppView.m */,
|
||||
FBDE86E719F82315001C18A8 /* App.h */,
|
||||
FBDE86E819F82315001C18A8 /* App.m */,
|
||||
);
|
||||
path = Limelight;
|
||||
sourceTree = "<group>";
|
||||
@@ -386,6 +387,8 @@
|
||||
FB89461219F646E200339C8A /* MDNSManager.m */,
|
||||
FB89461319F646E200339C8A /* PairManager.h */,
|
||||
FB89461419F646E200339C8A /* PairManager.m */,
|
||||
FBD3494119FC9C04002D2A60 /* AppManager.h */,
|
||||
FBD3494219FC9C04002D2A60 /* AppManager.m */,
|
||||
);
|
||||
path = Network;
|
||||
sourceTree = "<group>";
|
||||
@@ -410,6 +413,8 @@
|
||||
children = (
|
||||
FB89461F19F646E200339C8A /* Computer.h */,
|
||||
FB89462019F646E200339C8A /* Computer.m */,
|
||||
FBDE86E719F82315001C18A8 /* App.h */,
|
||||
FBDE86E819F82315001C18A8 /* App.m */,
|
||||
FB89462119F646E200339C8A /* Utils.h */,
|
||||
FB89462219F646E200339C8A /* Utils.m */,
|
||||
);
|
||||
@@ -725,6 +730,7 @@
|
||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
||||
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
|
||||
FB290D0019B2C406004C83CF /* main.m in Sources */,
|
||||
FBD3494319FC9C04002D2A60 /* AppManager.m in Sources */,
|
||||
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
||||
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
|
||||
);
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
|
||||
@interface App : NSObject
|
||||
|
||||
@property NSString* displayName;
|
||||
@property NSString* appId;
|
||||
@property NSString* appName;
|
||||
@property UIImage* appImage;
|
||||
|
||||
@end
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
//
|
||||
|
||||
#import "App.h"
|
||||
#import "HttpManager.h"
|
||||
|
||||
@implementation App
|
||||
@synthesize appId, appName, appImage;
|
||||
|
||||
@end
|
||||
|
||||
23
Limelight/Images.xcassets/AddComputer.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "limelight_computer_add_1x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "limelight_computer_add_2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "limelight_computer_add_3x.png"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/AddComputer.imageset/limelight_computer_add_1x.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
Limelight/Images.xcassets/AddComputer.imageset/limelight_computer_add_2x.png
vendored
Normal file
|
After Width: | Height: | Size: 15 KiB |
BIN
Limelight/Images.xcassets/AddComputer.imageset/limelight_computer_add_3x.png
vendored
Normal file
|
After Width: | Height: | Size: 25 KiB |
21
Limelight/Images.xcassets/AddComputerIcon.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "limelight_computer_add_icon_2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/AddComputerIcon.imageset/limelight_computer_add_icon_2x.png
vendored
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
@@ -3,7 +3,7 @@
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x",
|
||||
"filename" : "limelight_computer_2x-1.png"
|
||||
"filename" : "limelight_computer_1x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
@@ -13,7 +13,7 @@
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x",
|
||||
"filename" : "limelight_computer_2x-2.png"
|
||||
"filename" : "limelight_computer_3x.png"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
|
||||
BIN
Limelight/Images.xcassets/Computer.imageset/limelight_computer_1x.png
vendored
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
BIN
Limelight/Images.xcassets/Computer.imageset/limelight_computer_3x.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
21
Limelight/Images.xcassets/NoAppImage.imageset/Contents.json
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "1x"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "2x",
|
||||
"filename" : "limelight_no_app_image_2x.png"
|
||||
},
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"scale" : "3x"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
||||
BIN
Limelight/Images.xcassets/NoAppImage.imageset/limelight_no_app_image_2x.png
vendored
Normal file
|
After Width: | Height: | Size: 22 KiB |
23
Limelight/Network/AppManager.h
Normal file
@@ -0,0 +1,23 @@
|
||||
//
|
||||
// AppManager.h
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/25/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "App.h"
|
||||
#import "HttpManager.h"
|
||||
|
||||
@protocol AppAssetCallback <NSObject>
|
||||
|
||||
- (void) receivedAssetForApp:(App*)app;
|
||||
|
||||
@end
|
||||
|
||||
@interface AppManager : NSObject
|
||||
|
||||
+ (void) retrieveAppAssets:(NSArray*)apps withManager:(HttpManager*)hMan andCallback:(id<AppAssetCallback>)callback;
|
||||
|
||||
@end
|
||||
45
Limelight/Network/AppManager.m
Normal file
@@ -0,0 +1,45 @@
|
||||
//
|
||||
// AppManager.m
|
||||
// Limelight
|
||||
//
|
||||
// Created by Diego Waxemberg on 10/25/14.
|
||||
// Copyright (c) 2014 Limelight Stream. All rights reserved.
|
||||
//
|
||||
|
||||
#import "AppManager.h"
|
||||
|
||||
@implementation AppManager {
|
||||
App* _app;
|
||||
HttpManager* _hMan;
|
||||
id<AppAssetCallback> _callback;
|
||||
}
|
||||
|
||||
+ (void) retrieveAppAssets:(NSArray*)apps withManager:(HttpManager*)hMan andCallback:(id<AppAssetCallback>)callback {
|
||||
for (App* app in apps) {
|
||||
AppManager* manager = [[AppManager alloc] initWithApp:app httpManager:hMan andCallback:callback];
|
||||
[manager retrieveAsset];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (id) initWithApp:(App*)app httpManager:(HttpManager*)hMan andCallback:(id<AppAssetCallback>)callback {
|
||||
self = [super init];
|
||||
_app = app;
|
||||
_hMan = hMan;
|
||||
_callback = callback;
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) retrieveAsset {
|
||||
NSData* appAsset = [_hMan executeRequestSynchronously:[_hMan newAppAssetRequestWithAppId:_app.appId]];
|
||||
UIImage* appImage = [UIImage imageWithData:appAsset];
|
||||
_app.appImage = appImage;
|
||||
NSLog(@"App Name: %@ id:%@ image: %@", _app.appName, _app.appId, _app.appImage);
|
||||
[self performSelectorOnMainThread:@selector(sendCallBack) withObject:self waitUntilDone:NO];
|
||||
}
|
||||
|
||||
- (void) sendCallBack {
|
||||
[_callback receivedAssetForApp:_app];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
||||
|
||||
+ (NSArray*) getAppListFromXML:(NSData*)xml;
|
||||
+ (NSString*) getStringFromXML:(NSData*)xml tag:(NSString*)tag;
|
||||
+ (NSString*) getStatusStringFromXML:(NSData*)xml;
|
||||
|
||||
@@ -24,6 +25,7 @@
|
||||
- (NSURLRequest*) newServerInfoRequest;
|
||||
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid;
|
||||
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
|
||||
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
|
||||
- (NSData*) executeRequestSynchronously:(NSURLRequest*)request;
|
||||
@end
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#import "HttpManager.h"
|
||||
#import "CryptoManager.h"
|
||||
#import "App.h"
|
||||
|
||||
#include <libxml2/libxml/xmlreader.h>
|
||||
#include <string.h>
|
||||
@@ -25,6 +26,60 @@
|
||||
|
||||
static const NSString* PORT = @"47984";
|
||||
|
||||
+ (NSArray*) getAppListFromXML:(NSData*)xml {
|
||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
||||
|
||||
if (docPtr == NULL) {
|
||||
NSLog(@"ERROR: An error occured trying to parse xml.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
xmlNodePtr node;
|
||||
xmlNodePtr rootNode = node = xmlDocGetRootElement(docPtr);
|
||||
|
||||
// Check root status_code
|
||||
if (![HttpManager verifyStatus: rootNode]) {
|
||||
NSLog(@"ERROR: Request returned with failure status");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Skip the root node
|
||||
node = node->children;
|
||||
|
||||
NSMutableArray* appList = [[NSMutableArray alloc] init];
|
||||
|
||||
while (node != NULL) {
|
||||
NSLog(@"node: %s", node->name);
|
||||
if (!xmlStrcmp(node->name, (const xmlChar*)"App")) {
|
||||
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
||||
NSString* appName;
|
||||
NSString* appId;
|
||||
while (appInfoNode != NULL) {
|
||||
NSLog(@"appInfoNode: %s", appInfoNode->name);
|
||||
if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"AppTitle")) {
|
||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||
appName = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||
xmlFree(nodeVal);
|
||||
} else if (!xmlStrcmp(appInfoNode->name, (const xmlChar*)"ID")) {
|
||||
xmlChar* nodeVal = xmlNodeListGetString(docPtr, appInfoNode->xmlChildrenNode, 1);
|
||||
appId = [[NSString alloc] initWithCString:(const char*)nodeVal encoding:NSUTF8StringEncoding];
|
||||
xmlFree(nodeVal);
|
||||
}
|
||||
appInfoNode = appInfoNode->next;
|
||||
}
|
||||
App* app = [[App alloc] init];
|
||||
app.appName = appName;
|
||||
app.appId = appId;
|
||||
[appList addObject:app];
|
||||
}
|
||||
node = node->next;
|
||||
}
|
||||
xmlFree(rootNode);
|
||||
xmlFree(docPtr);
|
||||
|
||||
return appList;
|
||||
}
|
||||
|
||||
+ (NSString*) getStatusStringFromXML:(NSData*)xml {
|
||||
xmlDocPtr docPtr = xmlParseMemory([xml bytes], (int)[xml length]);
|
||||
|
||||
@@ -198,6 +253,11 @@ static const NSString* PORT = @"47984";
|
||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||
}
|
||||
|
||||
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId {
|
||||
NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseURL, _uniqueId, appId];
|
||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||
}
|
||||
|
||||
- (NSString*) bytesToHex:(NSData*)data {
|
||||
const unsigned char* bytes = [data bytes];
|
||||
NSMutableString *hex = [[NSMutableString alloc] init];
|
||||
@@ -217,7 +277,11 @@ static const NSString* PORT = @"47984";
|
||||
}
|
||||
|
||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
||||
_requestResp = [HttpManager fixXmlVersion:_respData];
|
||||
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
|
||||
_requestResp = [HttpManager fixXmlVersion:_respData];
|
||||
} else {
|
||||
_requestResp = _respData;
|
||||
}
|
||||
dispatch_semaphore_signal(_requestLock);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
- (void) showPIN:(NSString*)PIN;
|
||||
- (void) pairSuccessful;
|
||||
- (void) pairFailed:(NSString*)message;
|
||||
- (void) alreadyPaired;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -32,14 +32,13 @@
|
||||
[_callback pairFailed:@"Unable to connect to PC"];
|
||||
return;
|
||||
}
|
||||
|
||||
if (![[HttpManager getStringFromXML:serverInfo tag:@"currentgame"] isEqual:@"0"]) {
|
||||
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
||||
}
|
||||
else if (![[HttpManager getStringFromXML:serverInfo tag:@"PairStatus"] isEqual:@"1"]) {
|
||||
[self initiatePair];
|
||||
} else {
|
||||
[_callback pairFailed:@"This device is already paired."];
|
||||
[_callback alreadyPaired];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
@interface StreamConfiguration : NSObject
|
||||
|
||||
@property NSString* host;
|
||||
@property NSString* appID;
|
||||
@property int hostAddr;
|
||||
@property int width;
|
||||
@property int height;
|
||||
|
||||
@@ -9,5 +9,5 @@
|
||||
#import "StreamConfiguration.h"
|
||||
|
||||
@implementation StreamConfiguration
|
||||
@synthesize host, hostAddr, width, height, frameRate, bitRate, riKeyId, riKey;
|
||||
@synthesize host, appID, hostAddr, width, height, frameRate, bitRate, riKeyId, riKey;
|
||||
@end
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
||||
NSString* currentGame = [HttpManager getStringFromXML:serverInfoResp tag:@"currentgame"];
|
||||
NSString* pairStatus = [HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"];
|
||||
NSString* currentClient = [HttpManager getStringFromXML:serverInfoResp tag:@"CurrentClient"];
|
||||
if (currentGame == NULL || pairStatus == NULL) {
|
||||
[_callbacks launchFailed:@"Failed to connect to PC"];
|
||||
return;
|
||||
@@ -55,6 +56,11 @@
|
||||
|
||||
// resumeApp and launchApp handle calling launchFailed
|
||||
if (![currentGame isEqualToString:@"0"]) {
|
||||
if (![currentClient isEqualToString:@"1"]) {
|
||||
// The server is streaming to someone else
|
||||
[_callbacks launchFailed:@"There is another stream in progress"];
|
||||
return;
|
||||
}
|
||||
// App already running, resume it
|
||||
if (![self resumeApp:hMan]) {
|
||||
return;
|
||||
@@ -79,7 +85,7 @@
|
||||
|
||||
- (BOOL) launchApp:(HttpManager*)hMan {
|
||||
NSData* launchResp = [hMan executeRequestSynchronously:
|
||||
[hMan newLaunchRequest:@"67339056"
|
||||
[hMan newLaunchRequest:_config.appID
|
||||
width:_config.width
|
||||
height:_config.height
|
||||
refreshRate:_config.frameRate
|
||||
|
||||
@@ -9,8 +9,15 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "App.h"
|
||||
|
||||
@interface UIAppView : UIView
|
||||
@protocol AppCallback <NSObject>
|
||||
|
||||
- (id) initWithApp:(App*)app;
|
||||
- (void) appClicked:(App*) app;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIAppView : UIView
|
||||
|
||||
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback;
|
||||
- (void) updateAppImage;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,32 +12,54 @@
|
||||
App* _app;
|
||||
UIButton* _appButton;
|
||||
UILabel* _appLabel;
|
||||
id<AppCallback> _callback;
|
||||
}
|
||||
static int LABEL_DY = 20;
|
||||
|
||||
- (id) initWithApp:(App*)app {
|
||||
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback {
|
||||
self = [super init];
|
||||
_app = app;
|
||||
_callback = callback;
|
||||
|
||||
_appButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_appButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
|
||||
[_appButton setBackgroundImage:[[UIImage imageNamed:@"Left4Dead2"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)] forState:UIControlStateNormal];
|
||||
[_appButton setBackgroundImage:[UIImage imageNamed:@"NoAppImage"] forState:UIControlStateNormal];
|
||||
[_appButton sizeToFit];
|
||||
[_appButton addTarget:self action:@selector(appClicked) forControlEvents:UIControlEventTouchUpInside];
|
||||
_appButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
||||
_appButton.layer.shadowOffset = CGSizeMake(5,8);
|
||||
_appButton.layer.shadowOpacity = 0.7;
|
||||
|
||||
_appLabel = [[UILabel alloc] init];
|
||||
[_appLabel setText:_app.displayName];
|
||||
[_appLabel setText:_app.appName];
|
||||
[_appLabel sizeToFit];
|
||||
_appLabel.center = CGPointMake(_appButton.bounds.origin.x + (_appButton.bounds.size.width / 2), _appButton.bounds.origin.y + _appButton.bounds.size.height + LABEL_DY);
|
||||
|
||||
[self updateBounds];
|
||||
[self addSubview:_appButton];
|
||||
[self addSubview:_appLabel];
|
||||
|
||||
self.frame = CGRectMake(0, 0, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) updateBounds {
|
||||
float x = _appButton.frame.origin.x < _appLabel.frame.origin.x ? _appButton.frame.origin.x : _appLabel.frame.origin.x;
|
||||
float y = _appButton.frame.origin.y < _appLabel.frame.origin.y ? _appButton.frame.origin.y : _appLabel.frame.origin.y;
|
||||
self.bounds = CGRectMake(x , y, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height + LABEL_DY / 2);
|
||||
self.frame = CGRectMake(x , y, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height + LABEL_DY / 2);
|
||||
}
|
||||
|
||||
- (void) appClicked {
|
||||
[_callback appClicked:_app];
|
||||
}
|
||||
|
||||
- (void) updateAppImage {
|
||||
if (_app.appImage != nil) {
|
||||
[_appButton setBackgroundImage:_app.appImage forState:UIControlStateNormal];
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
|
||||
@@ -9,8 +9,16 @@
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "Computer.h"
|
||||
|
||||
@interface UIComputerView : UIView
|
||||
@protocol HostCallback <NSObject>
|
||||
|
||||
- (id) initWithComputer:(Computer*)computer;
|
||||
- (void) hostClicked:(Computer*)computer;
|
||||
- (void) addHostClicked;
|
||||
|
||||
@end
|
||||
|
||||
@interface UIComputerView : UIView
|
||||
|
||||
- (id) initWithComputer:(Computer*)computer andCallback:(id<HostCallback>)callback;
|
||||
- (id) initForAddWithCallback:(id<HostCallback>)callback;
|
||||
|
||||
@end
|
||||
|
||||
@@ -12,31 +12,82 @@
|
||||
Computer* _computer;
|
||||
UIButton* _hostButton;
|
||||
UILabel* _hostLabel;
|
||||
id<HostCallback> _callback;
|
||||
CGSize _labelSize;
|
||||
}
|
||||
static int LABEL_DY = 20;
|
||||
|
||||
- (id) initWithComputer:(Computer*)computer {
|
||||
- (id) init {
|
||||
self = [super init];
|
||||
_computer = computer;
|
||||
|
||||
_hostButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
[_hostButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
|
||||
[_hostButton setBackgroundImage:[[UIImage imageNamed:@"Computer"] resizableImageWithCapInsets:UIEdgeInsetsMake(10, 10, 10, 10)] forState:UIControlStateNormal];
|
||||
[_hostButton setBackgroundImage:[UIImage imageNamed:@"Computer"] forState:UIControlStateNormal];
|
||||
[_hostButton sizeToFit];
|
||||
|
||||
_hostButton.layer.shadowColor = [[UIColor blackColor] CGColor];
|
||||
_hostButton.layer.shadowOffset = CGSizeMake(5,8);
|
||||
_hostButton.layer.shadowOpacity = 0.7;
|
||||
|
||||
_hostLabel = [[UILabel alloc] init];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initWithComputer:(Computer*)computer andCallback:(id<HostCallback>)callback {
|
||||
self = [self init];
|
||||
_computer = computer;
|
||||
_callback = callback;
|
||||
|
||||
[_hostLabel setText:[_computer displayName]];
|
||||
[_hostLabel sizeToFit];
|
||||
_hostLabel.center = CGPointMake(_hostButton.bounds.origin.x + (_hostButton.bounds.size.width / 2), _hostButton.bounds.origin.y + _hostButton.bounds.size.height + LABEL_DY);
|
||||
|
||||
[_hostButton addTarget:self action:@selector(hostClicked) forControlEvents:UIControlEventTouchUpInside];
|
||||
_hostLabel.center = CGPointMake(_hostButton.frame.origin.x + (_hostButton.frame.size.width / 2), _hostButton.frame.origin.y + _hostButton.frame.size.height + LABEL_DY);
|
||||
[self updateBounds];
|
||||
[self addSubview:_hostButton];
|
||||
[self addSubview:_hostLabel];
|
||||
|
||||
self.frame = CGRectMake(0, 0, _hostButton.frame.size.width > _hostLabel.frame.size.width ? _hostButton.frame.size.width : _hostLabel.frame.size.width, _hostButton.frame.size.height + _hostLabel.frame.size.height);
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) updateBounds {
|
||||
float x = _hostButton.frame.origin.x < _hostLabel.frame.origin.x ? _hostButton.frame.origin.x : _hostLabel.frame.origin.x;
|
||||
float y = _hostButton.frame.origin.y < _hostLabel.frame.origin.y ? _hostButton.frame.origin.y : _hostLabel.frame.origin.y;
|
||||
self.bounds = CGRectMake(x , y, _hostButton.frame.size.width > _hostLabel.frame.size.width ? _hostButton.frame.size.width : _hostLabel.frame.size.width, _hostButton.frame.size.height + _hostLabel.frame.size.height + LABEL_DY / 2);
|
||||
self.frame = CGRectMake(x , y, _hostButton.frame.size.width > _hostLabel.frame.size.width ? _hostButton.frame.size.width : _hostLabel.frame.size.width, _hostButton.frame.size.height + _hostLabel.frame.size.height + LABEL_DY / 2);
|
||||
}
|
||||
|
||||
- (id) initForAddWithCallback:(id<HostCallback>)callback {
|
||||
self = [self init];
|
||||
_callback = callback;
|
||||
|
||||
[_hostButton setBackgroundImage:[UIImage imageNamed:@"Computer"] forState:UIControlStateNormal];
|
||||
[_hostButton sizeToFit];
|
||||
[_hostButton addTarget:self action:@selector(addClicked) forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[_hostLabel setText:@"Add Host"];
|
||||
[_hostLabel sizeToFit];
|
||||
_hostLabel.center = CGPointMake(_hostButton.frame.origin.x + (_hostButton.frame.size.width / 2), _hostButton.frame.origin.y + _hostButton.frame.size.height + LABEL_DY);
|
||||
|
||||
UIImageView* addIcon = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"AddComputerIcon"]];
|
||||
[addIcon sizeToFit];
|
||||
addIcon.center = CGPointMake(_hostButton.frame.origin.x + _hostButton.frame.size.width, _hostButton.frame.origin.y);
|
||||
|
||||
[self updateBounds];
|
||||
[self addSubview:_hostButton];
|
||||
[self addSubview:_hostLabel];
|
||||
[self addSubview:addIcon];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) hostClicked {
|
||||
[_callback hostClicked:_computer];
|
||||
}
|
||||
|
||||
- (void) addClicked {
|
||||
[_callback addHostClicked];
|
||||
}
|
||||
|
||||
/*
|
||||
// Only override drawRect: if you perform custom drawing.
|
||||
// An empty implementation adversely affects performance during animation.
|
||||
|
||||
@@ -15,6 +15,5 @@
|
||||
|
||||
- (id) initWithHost:(NSNetService*)host;
|
||||
- (id) initWithIp:(NSString*)host;
|
||||
- (id) initPlaceholder;
|
||||
|
||||
@end
|
||||
|
||||
@@ -28,13 +28,4 @@
|
||||
return self;
|
||||
}
|
||||
|
||||
- (id) initPlaceholder {
|
||||
self = [super init];
|
||||
|
||||
self.hostName = NULL;
|
||||
self.displayName = @"No computers found";
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
#import "MDNSManager.h"
|
||||
#import "PairManager.h"
|
||||
#import "StreamConfiguration.h"
|
||||
#import "UIComputerView.h"
|
||||
#import "UIAppView.h"
|
||||
#import "AppManager.h"
|
||||
|
||||
@interface MainFrameViewController : UIViewController <MDNSCallback, PairCallback, NSURLConnectionDelegate>
|
||||
@interface MainFrameViewController : UIViewController <MDNSCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate>
|
||||
|
||||
+ (StreamConfiguration*) getStreamConfiguration;
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
|
||||
// MainFrameViewController.m
|
||||
// Limelight-iOS
|
||||
//
|
||||
@@ -22,45 +21,21 @@
|
||||
NSOperationQueue* _opQueue;
|
||||
MDNSManager* _mDNSManager;
|
||||
Computer* _selectedHost;
|
||||
NSString* _uniqueId;
|
||||
NSData* _cert;
|
||||
|
||||
UIAlertView* _pairAlert;
|
||||
UIScrollView* hostScrollView;
|
||||
UIScrollView* appScrollView;
|
||||
}
|
||||
static NSString* deviceName = @"roth";
|
||||
static NSMutableSet* hostList;
|
||||
static StreamConfiguration* streamConfig;
|
||||
|
||||
+ (StreamConfiguration*) getStreamConfiguration {
|
||||
return streamConfig;
|
||||
}
|
||||
|
||||
//TODO: no more pair button
|
||||
/*
|
||||
- (void)PairButton:(UIButton *)sender
|
||||
{
|
||||
NSLog(@"Pair Button Pressed!");
|
||||
if ([self.hostTextField.text length] > 0) {
|
||||
_selectedHost = [[Computer alloc] initWithIp:self.hostTextField.text];
|
||||
NSLog(@"Using custom host: %@", self.hostTextField.text);
|
||||
}
|
||||
|
||||
if (![self validatePcSelected]) {
|
||||
NSLog(@"No valid PC selected");
|
||||
return;
|
||||
}
|
||||
|
||||
[CryptoManager generateKeyPairUsingSSl];
|
||||
NSString* uniqueId = [CryptoManager getUniqueID];
|
||||
NSData* cert = [CryptoManager readCertFromFile];
|
||||
|
||||
if ([Utils resolveHost:_selectedHost.hostName] == 0) {
|
||||
[self displayDnsFailedDialog];
|
||||
return;
|
||||
}
|
||||
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.hostName uniqueId:uniqueId deviceName:@"roth" cert:cert];
|
||||
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:cert callback:self];
|
||||
|
||||
[_opQueue addOperation:pMan];
|
||||
}
|
||||
*/
|
||||
|
||||
- (void)showPIN:(NSString *)PIN {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing" message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
||||
@@ -84,6 +59,26 @@ static StreamConfiguration* streamConfig;
|
||||
});
|
||||
}
|
||||
|
||||
- (void)alreadyPaired {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.hostName uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||
NSData* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]];
|
||||
NSArray* appList = [HttpManager getAppListFromXML:appListResp];
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self updateApps:appList];
|
||||
});
|
||||
[AppManager retrieveAppAssets:appList withManager:hMan andCallback:self];
|
||||
});
|
||||
}
|
||||
|
||||
- (void) receivedAssetForApp:(App*)app {
|
||||
NSArray* subviews = [appScrollView subviews];
|
||||
for (UIAppView* appView in subviews) {
|
||||
[appView updateAppImage];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)displayDnsFailedDialog {
|
||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Network Error"
|
||||
message:@"Failed to resolve host."
|
||||
@@ -92,31 +87,55 @@ static StreamConfiguration* streamConfig;
|
||||
[self presentViewController:alert animated:YES completion:nil];
|
||||
}
|
||||
|
||||
//TODO: No more stream button
|
||||
/*
|
||||
- (void)StreamButton:(UIButton *)sender
|
||||
{
|
||||
NSLog(@"Stream Button Pressed!");
|
||||
|
||||
if ([self.hostTextField.text length] > 0) {
|
||||
_selectedHost = [[Computer alloc] initWithIp:self.hostTextField.text];
|
||||
NSLog(@"Using custom host: %@", self.hostTextField.text);
|
||||
}
|
||||
|
||||
if (![self validatePcSelected]) {
|
||||
NSLog(@"No valid PC selected");
|
||||
return;
|
||||
}
|
||||
|
||||
- (void) hostClicked:(Computer *)computer {
|
||||
NSLog(@"Clicked host: %@", computer.displayName);
|
||||
_selectedHost = computer;
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:computer.hostName uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
||||
if ([[HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"] isEqualToString:@"1"]) {
|
||||
NSLog(@"Already Paired");
|
||||
[self alreadyPaired];
|
||||
} else {
|
||||
NSLog(@"Trying to pair");
|
||||
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
|
||||
[_opQueue addOperation:pMan];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void) addHostClicked {
|
||||
NSLog(@"Clicked add host");
|
||||
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:@"Host Address" message:@"Please enter a hostname or IP address" preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
NSString* host = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text;
|
||||
Computer* newHost = [[Computer alloc] initWithIp:host];
|
||||
[hostList addObject:newHost];
|
||||
[self updateHosts:[hostList allObjects]];
|
||||
|
||||
|
||||
//TODO: get pair state
|
||||
|
||||
|
||||
}]];
|
||||
[alertController addTextFieldWithConfigurationHandler:nil];
|
||||
[self presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void) appClicked:(App *)app {
|
||||
NSLog(@"Clicked app: %@", app.appName);
|
||||
streamConfig = [[StreamConfiguration alloc] init];
|
||||
streamConfig.host = _selectedHost.hostName;
|
||||
streamConfig.hostAddr = [Utils resolveHost:_selectedHost.hostName];
|
||||
streamConfig.appID = app.appId;
|
||||
if (streamConfig.hostAddr == 0) {
|
||||
[self displayDnsFailedDialog];
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned long selectedConf = [self.StreamConfigs selectedRowInComponent:0];
|
||||
// TODO: actually allow the user to choose the config
|
||||
unsigned long selectedConf = 1;
|
||||
NSLog(@"selectedConf: %ld", selectedConf);
|
||||
switch (selectedConf) {
|
||||
case 0:
|
||||
@@ -148,19 +167,6 @@ static StreamConfiguration* streamConfig;
|
||||
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)setSelectedHost:(NSInteger)selectedIndex
|
||||
{
|
||||
_selectedHost = (Computer*)([self.hostPickerVals objectAtIndex:selectedIndex]);
|
||||
if (_selectedHost.hostName == NULL) {
|
||||
// This must be the placeholder computer
|
||||
_selectedHost = NULL;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
@@ -169,68 +175,91 @@ static StreamConfiguration* streamConfig;
|
||||
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
|
||||
//[self updateHosts:[[NSArray alloc] init]];
|
||||
if (hostList == nil) {
|
||||
hostList = [[NSMutableSet alloc] init];
|
||||
}
|
||||
|
||||
Computer* test = [[Computer alloc] initWithIp:@"CEMENT-TRUCK"];
|
||||
|
||||
|
||||
UIScrollView* hostScrollView = [[UIScrollView alloc] init];
|
||||
hostScrollView = [[UIScrollView alloc] init];
|
||||
hostScrollView.frame = CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height / 2);
|
||||
[hostScrollView setShowsHorizontalScrollIndicator:NO];
|
||||
UIComputerView* compView;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
compView = [[UIComputerView alloc] initWithComputer:test];
|
||||
[hostScrollView addSubview:compView];
|
||||
[compView sizeToFit];
|
||||
compView.center = CGPointMake((compView.frame.size.width + 20) * i + compView.frame.size.width, hostScrollView.frame.size.height / 2);
|
||||
|
||||
}
|
||||
|
||||
[hostScrollView setContentSize:CGSizeMake(compView.frame.size.width * 5 + compView.frame.size.width, hostScrollView.frame.size.height)];
|
||||
|
||||
|
||||
UIScrollView* appScrollView = [[UIScrollView alloc] init];
|
||||
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];
|
||||
|
||||
|
||||
App* testApp = [[App alloc] init];
|
||||
testApp.displayName = @"Left 4 Dead 2";
|
||||
UIAppView* appView;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
appView = [[UIAppView alloc] initWithApp:testApp];
|
||||
[appScrollView addSubview:appView];
|
||||
[appView sizeToFit];
|
||||
appView.center = CGPointMake((appView.frame.size.width + 20) * i + compView.frame.size.width, appScrollView.frame.size.height / 2);
|
||||
}
|
||||
|
||||
[appScrollView setContentSize:CGSizeMake(appView.frame.size.width * 5 + appView.frame.size.width, appScrollView.frame.size.height)];
|
||||
|
||||
|
||||
[self updateHosts:[hostList allObjects]];
|
||||
[self.view addSubview:hostScrollView];
|
||||
[self.view addSubview:appScrollView];
|
||||
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
//_mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
||||
// [_mDNSManager searchForHosts];
|
||||
_mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
||||
[_mDNSManager searchForHosts];
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
// [_mDNSManager stopSearching];
|
||||
[_mDNSManager stopSearching];
|
||||
}
|
||||
|
||||
- (void)updateHosts:(NSArray *)hosts {
|
||||
NSMutableArray *hostPickerValues = [[NSMutableArray alloc] initWithArray:hosts];
|
||||
[hostList addObjectsFromArray:hosts];
|
||||
[[hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self];
|
||||
UIComputerView* compView;
|
||||
float prevEdge = -1;
|
||||
for (Computer* comp in hostList) {
|
||||
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
|
||||
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
|
||||
prevEdge = compView.frame.origin.x + compView.frame.size.width;
|
||||
[hostScrollView addSubview:compView];
|
||||
}
|
||||
|
||||
if ([hostPickerValues count] == 0) {
|
||||
[hostPickerValues addObject:[[Computer alloc] initPlaceholder]];
|
||||
prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
|
||||
addComp.center = CGPointMake(prevEdge, hostScrollView.frame.size.height / 2);
|
||||
|
||||
[hostScrollView addSubview:addComp];
|
||||
[hostScrollView setContentSize:CGSizeMake(prevEdge + addComp.frame.size.width, hostScrollView.frame.size.height)];
|
||||
}
|
||||
|
||||
- (float) getCompViewX:(UIComputerView*)comp addComp:(UIComputerView*)addComp prevEdge:(float)prevEdge {
|
||||
if (prevEdge == -1) {
|
||||
return hostScrollView.frame.origin.x + comp.frame.size.width / 2 + addComp.frame.size.width / 2;
|
||||
} else {
|
||||
return prevEdge + addComp.frame.size.width / 2 + comp.frame.size.width / 2;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateApps:(NSArray*)apps {
|
||||
[[appScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
||||
App* fakeApp = [[App alloc] init];
|
||||
fakeApp.appName = @"No App Name";
|
||||
UIAppView* noAppImage = [[UIAppView alloc] initWithApp:fakeApp andCallback:nil];
|
||||
float prevEdge = -1;
|
||||
UIAppView* appView;
|
||||
for (App* app in apps) {
|
||||
appView = [[UIAppView alloc] initWithApp:app andCallback:self];
|
||||
prevEdge = [self getAppViewX:appView noApp:noAppImage prevEdge:prevEdge];
|
||||
appView.center = CGPointMake(prevEdge, appScrollView.frame.size.height / 2);
|
||||
prevEdge = appView.frame.origin.x + appView.frame.size.width;
|
||||
[appScrollView addSubview:appView];
|
||||
}
|
||||
[appScrollView setContentSize:CGSizeMake(prevEdge + noAppImage.frame.size.width, appScrollView.frame.size.height)];
|
||||
}
|
||||
|
||||
- (float) getAppViewX:(UIAppView*)app noApp:(UIAppView*)noAppImage prevEdge:(float)prevEdge {
|
||||
if (prevEdge == -1) {
|
||||
return appScrollView.frame.origin.x + app.frame.size.width / 2 + noAppImage.frame.size.width / 2;
|
||||
} else {
|
||||
return prevEdge + app.frame.size.width / 2 + noAppImage.frame.size.width / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
[super viewDidLoad];
|
||||
|
||||
[self.stageLabel setText:@"Starting App"];
|
||||
[self.stageLabel sizeToFit];
|
||||
self.stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self.stageLabel.center.y);
|
||||
|
||||
[UIApplication sharedApplication].idleTimerDisabled = YES;
|
||||
|
||||
@@ -53,6 +55,8 @@
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
[self.spinner stopAnimating];
|
||||
[self.stageLabel setText:@"Waiting for first frame..."];
|
||||
[self.stageLabel sizeToFit];
|
||||
self.stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self.stageLabel.center.y);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -74,6 +78,8 @@
|
||||
NSString* lowerCase = [NSString stringWithFormat:@"%s in progress...", stageName];
|
||||
NSString* titleCase = [[[lowerCase substringToIndex:1] uppercaseString] stringByAppendingString:[lowerCase substringFromIndex:1]];
|
||||
[self.stageLabel setText:titleCase];
|
||||
[self.stageLabel sizeToFit];
|
||||
self.stageLabel.center = CGPointMake(self.view.frame.size.width / 2, self.stageLabel.center.y);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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.iPad" propertyAccessControl="none" useAutolayout="YES" initialViewController="wb7-af-jn8">
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="6250" systemVersion="14A388a" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="wb7-af-jn8">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
</dependencies>
|
||||
@@ -8,21 +8,9 @@
|
||||
<scene sceneID="Me4-Nr-liz">
|
||||
<objects>
|
||||
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="bBC-Wp-X5U"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="QeP-va-uIv"/>
|
||||
</layoutGuides>
|
||||
<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>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xyV-op-tQY">
|
||||
<rect key="frame" x="564" y="470" width="42" height="21"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||
@@ -38,31 +26,23 @@
|
||||
<scene sceneID="RuD-qk-7nb">
|
||||
<objects>
|
||||
<viewController storyboardIdentifier="MainFrame" id="OIm-0n-i9v" customClass="StreamFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="NG3-N1-D4k"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="3MH-n6-BSR"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="VPm-Ae-rc4" userLabel="RenderView" customClass="StreamView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="iOs-1X-mSU">
|
||||
<activityIndicatorView opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" id="iOs-1X-mSU">
|
||||
<rect key="frame" x="502" y="374" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="dDs-kT-po6">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dDs-kT-po6">
|
||||
<rect key="frame" x="491" y="402" width="42" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstItem="dDs-kT-po6" firstAttribute="top" secondItem="iOs-1X-mSU" secondAttribute="bottom" constant="8" id="VZj-wk-dHp"/>
|
||||
<constraint firstAttribute="centerY" secondItem="iOs-1X-mSU" secondAttribute="centerY" id="YAN-0k-Rds"/>
|
||||
<constraint firstAttribute="centerX" secondItem="dDs-kT-po6" secondAttribute="centerX" id="bLr-5Z-OH3"/>
|
||||
<constraint firstAttribute="centerX" secondItem="iOs-1X-mSU" secondAttribute="centerX" id="ruD-8B-gj3"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<?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" useAutolayout="YES" 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="dgh-JZ-Q7z">
|
||||
<dependencies>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6244"/>
|
||||
</dependencies>
|
||||
@@ -8,10 +8,6 @@
|
||||
<scene sceneID="emz-kO-L7q">
|
||||
<objects>
|
||||
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="udy-Vd-ca2"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="wiU-k0-6Q2"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="RId-Pb-IBX">
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
@@ -32,31 +28,23 @@
|
||||
<scene sceneID="5Eb-q2-vjt">
|
||||
<objects>
|
||||
<viewController id="mI3-9F-XwU" customClass="StreamFrameViewController" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="DRq-YB-9Rh"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="KH1-hM-RYW"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="eir-e9-IPE" customClass="StreamView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<subviews>
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" translatesAutoresizingMaskIntoConstraints="NO" id="0vm-Iv-K4b">
|
||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" hidesWhenStopped="YES" animating="YES" style="white" id="0vm-Iv-K4b">
|
||||
<rect key="frame" x="274" y="150" width="20" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
</activityIndicatorView>
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2HK-Z5-4Ch">
|
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stage" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="2HK-Z5-4Ch">
|
||||
<rect key="frame" x="262" y="178" width="45" height="21"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||
<nil key="highlightedColor"/>
|
||||
</label>
|
||||
</subviews>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="centerX" secondItem="2HK-Z5-4Ch" secondAttribute="centerX" constant="-0.5" id="Blw-Hy-66z"/>
|
||||
<constraint firstAttribute="centerX" secondItem="0vm-Iv-K4b" secondAttribute="centerX" id="mCQ-CP-Yik"/>
|
||||
<constraint firstAttribute="centerY" secondItem="0vm-Iv-K4b" secondAttribute="centerY" id="t8e-qp-g1j"/>
|
||||
<constraint firstItem="2HK-Z5-4Ch" firstAttribute="top" secondItem="0vm-Iv-K4b" secondAttribute="bottom" constant="8" id="tta-Uo-bBO"/>
|
||||
</constraints>
|
||||
</view>
|
||||
<nil key="simulatedStatusBarMetrics"/>
|
||||
<nil key="simulatedTopBarMetrics"/>
|
||||
|
||||