Compare commits

..
32 Commits
Author SHA1 Message Date
Diego Waxemberg 55d48101ef Bumped build version
This is the first attempt at submission to the App Store
2015-11-01 00:12:39 -07:00
Cameron Gutman c36f4c5f84 Remove abort calls 2015-10-31 23:45:37 -07:00
Diego Waxemberg 06289ac4d2 No longer use IDFA, now generate UUID and persist in Core Data. Bumped version to 1.0.0 2015-10-31 23:04:32 -07:00
Cameron Gutman e6a2d5d425 Update project file after Xcode 7.1 2015-10-31 19:00:44 -07:00
Cameron Gutman ea8db9c4ea Update common with new bitrate logic 2015-10-31 19:00:05 -07:00
Cameron Gutman 3773e841d1 Update common to support GFE 2.7 2015-10-25 13:28:24 -07:00
Diego Waxemberg ad1ddd04f3 no longer allow multiple apps to be selected at the same time 2015-10-18 16:52:14 -07:00
Diego Waxemberg 67a8b232b9 added pull arrow to side of screen 2015-10-17 16:16:13 -07:00
Diego Waxemberg 5293c07fc0 fixed issue where we wouldn't terminate the stream on failure 2015-10-17 03:46:09 -07:00
Diego Waxemberg e3a42db007 On-screen controls revamp
- controls are bigger
- dead zone around buttons to avoid accidental mouse clicks and movement
- finished implementing control setup for AutoGCGamepad
- swiping to close stream requires swipe to 1/4 the screen width
- no longer send mouse movement if delta is too small
2015-10-17 03:02:55 -07:00
Diego Waxemberg 3b1462af22 removed support for native resolution stream 2015-10-16 23:38:14 -07:00
Cameron Gutman 74a0c5b1cd Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-09-30 20:44:26 -07:00
Cameron Gutman 05a5e4fa64 Fix a crash when apps are removed from GFE 2015-09-30 20:44:14 -07:00
Cameron Gutman b6445295a7 Use a temporary app object and database lock to avoid saving while the database is not in a consistent state 2015-09-30 20:34:52 -07:00
Diego Waxemberg 391605ef36 ignored the new xcsmblueprint files 2015-09-30 19:18:21 -07:00
Diego Waxemberg 695499dea9 host and app buttons now have feedback when tapped 2015-09-30 19:13:37 -07:00
Cameron Gutman 9ba7f35444 Require full-screen since the streaming game will be the primary interaction for the device 2015-09-30 18:00:52 -07:00
Cameron Gutman 37dc00735b Enabling bit code is causing linker errors when deploying to real devices for some reason. Turning it back off. 2015-09-29 00:06:27 -07:00
Cameron Gutman 920cbadc91 Add a workaround/hack to fix duplicating machines 2015-09-29 00:04:40 -07:00
Cameron Gutman bc53b4dc32 First stab at fixing on screen controls on various devices 2015-09-28 23:20:27 -07:00
Cameron Gutman 6015c38d17 Only display the native resolution dialog if the user has just chosen native resolution. Make the dialog a little nicer too. 2015-09-28 22:50:54 -07:00
Cameron Gutman 4ea8694a7d Fix status bar hiding while streaming on iPad 2015-09-28 21:49:46 -07:00
Cameron Gutman 00f01196fb Update placeholder app images to be the correct aspect ratio and invert the colors to better show against the new background 2015-09-28 21:40:10 -07:00
Diego Waxemberg 543639c93e Merge branch 'master' of github.com:moonlight-stream/moonlight-ios 2015-09-28 21:19:18 -07:00
Diego Waxemberg 1da877fed7 Changed theme to light/dark gray and updated launch screen. Also added a border and drop shadow to app icons 2015-09-28 21:18:35 -07:00
Cameron Gutman 396b5fc156 Update common 2015-09-28 19:22:28 -07:00
Cameron Gutman 297dfd4159 Update project file
- Change organization name
- Enable bit code
- Update Xcode compatibility version
2015-09-28 19:09:49 -07:00
Cameron Gutman 23e9d48b0d Update common-c and use the new LiInitializeXXX() functions 2015-08-16 12:27:21 -07:00
Cameron Gutman 9ec650a84f Zero audio renderer callbacks before populating 2015-08-12 01:18:22 -07:00
Cameron Gutman 90bdbc4ae0 Update common library 2015-08-12 01:11:38 -07:00
Cameron Gutman dd5f06723b Update common library to get assertions and a GFE 2.5.11 fix 2015-07-20 17:37:13 -07:00
Michelle Bergeron 55b2871b83 Update about beta program 2015-07-16 16:14:28 -07:00
61 changed files with 838 additions and 297 deletions
+1
View File
@@ -1,2 +1,3 @@
**/xcuserdata/
**/Moonlight.xcscmblueprint
Build
+42 -27
View File
@@ -1,36 +1,51 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8121.17" systemVersion="15A204h" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="8191" systemVersion="15A279b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8101.14"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text=" Copyright (c) 2015 Moonlight Stream. All rights reserved." textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" minimumFontSize="9" translatesAutoresizingMaskIntoConstraints="NO" id="8ie-xW-0ye">
<rect key="frame" x="18" y="439.5" width="444" height="20.5"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
<variation key="widthClass=compact">
<fontDescription key="fontDescription" type="system" pointSize="11"/>
</variation>
</label>
</subviews>
<animations/>
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
<constraints>
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/>
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
</constraints>
<nil key="simulatedStatusBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<point key="canvasLocation" x="404" y="445"/>
</view>
<navigationController id="vV9-32-ww6">
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</navigationBar>
<viewControllers>
<viewController id="l6V-ue-5Om">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
<viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="rW0-BH-s7l">
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
<rect key="frame" x="-23" y="-15" width="46" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<color key="titleShadowColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</state>
<variation key="widthClass=regular" preservesSuperviewLayoutMargins="NO"/>
</button>
</barButtonItem>
</navigationItem>
</viewController>
</viewControllers>
</navigationController>
</objects>
<resources>
<image name="Logo" width="32" height="32"/>
</resources>
</document>
+13
View File
@@ -0,0 +1,13 @@
//
// AppCollectionView.h
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppCollectionView : UICollectionView
@end
+28
View File
@@ -0,0 +1,28 @@
//
// AppCollectionView.m
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "AppCollectionView.h"
@implementation AppCollectionView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
+10 -30
View File
@@ -83,10 +83,7 @@ static NSOperationQueue* mainQueue;
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
if (managedObjectContext != nil) {
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
// Replace this implementation with code to handle the error appropriately.
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort();
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
}
}
}
@@ -136,32 +133,15 @@ static NSOperationQueue* mainQueue;
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
/*
Replace this implementation with code to handle the error appropriately.
abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
Typical reasons for an error here include:
* The persistent store is not accessible;
* The schema for the persistent store is incompatible with current managed object model.
Check the error message to determine what the actual problem was.
If the persistent store is not accessible, there is typically something wrong with the file path. Often, a file URL is pointing into the application's resources directory instead of a writeable directory.
If you encounter schema incompatibility errors during development, you can reduce their frequency by:
* Simply deleting the existing store:
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil]
* Performing automatic lightweight migration by passing the following dictionary as the options parameter:
@{NSMigratePersistentStoresAutomaticallyOption:@YES, NSInferMappingModelAutomaticallyOption:@YES}
Lightweight migration will only work for a limited set of schema changes; consult "Core Data Model Versioning and Data Migration Programming Guide" for details.
*/
Log(LOG_E, @"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
// Log the error
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
// Drop the database
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
// Try again
return [self persistentStoreCoordinator];
}
return _persistentStoreCoordinator;
}
+13
View File
@@ -0,0 +1,13 @@
//
// ComputerScrollView.h
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ComputerScrollView : UIScrollView
@end
+28
View File
@@ -0,0 +1,28 @@
//
// ComputerScrollView.m
// Moonlight
//
// Created by Diego Waxemberg on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "ComputerScrollView.h"
@implementation ComputerScrollView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}
/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
// Drawing code
}
*/
@end
-1
View File
@@ -11,7 +11,6 @@
@interface CryptoManager : NSObject
+ (void) generateKeyPairUsingSSl;
+ (NSString*) getUniqueID;
+ (NSData*) readCertFromFile;
+ (NSData*) readKeyFromFile;
+ (NSData*) readP12FromFile;
-15
View File
@@ -8,7 +8,6 @@
#import "CryptoManager.h"
#import "mkcert.h"
#import <AdSupport/ASIdentifierManager.h>
#include <openssl/aes.h>
#include <openssl/sha.h>
@@ -229,18 +228,4 @@ static NSData* p12 = nil;
});
}
+ (NSString*) getUniqueID {
// generate a UUID
NSUUID* uuid = [ASIdentifierManager sharedManager].advertisingIdentifier;
NSString* idString = [NSString stringWithString:[uuid UUIDString]];
// we need a 16byte hex-string so we take the last 17 characters
// and remove the '-' to get a 16 character string
NSMutableString* uniqueId = [NSMutableString stringWithString:[idString substringFromIndex:19]];
[uniqueId deleteCharactersInRange:NSMakeRange(4, 1)];
//Log(LOG_D, @"Unique ID: %@", uniqueId);
return [NSString stringWithString:uniqueId];
}
@end
+15
View File
@@ -0,0 +1,15 @@
//
// IdManager.h
// Moonlight
//
// Created by Diego Waxemberg on 10/31/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface IdManager : NSObject
+ (NSString*) getUniqueId;
@end
+33
View File
@@ -0,0 +1,33 @@
//
// IdManager.m
// Moonlight
//
// Created by Diego Waxemberg on 10/31/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "IdManager.h"
#import "DataManager.h"
@implementation IdManager
+ (NSString*) getUniqueId {
DataManager* dataMan = [[DataManager alloc] init];
Settings* prefs = [dataMan retrieveSettings];
NSString* uniqueId = prefs.uniqueId;
if (uniqueId == nil) {
uniqueId = [IdManager generateUniqueId];
prefs.uniqueId = uniqueId;
[dataMan saveData];
Log(LOG_I, @"No UUID found. Generated new UUID: %@", uniqueId);
}
return uniqueId;
}
+ (NSString*) generateUniqueId {
UInt64 uuidLong = ((UInt64) arc4random() << 32) | arc4random();
return [NSString stringWithFormat:@"%016llx", uuidLong];
}
@end
-2
View File
@@ -85,7 +85,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
if (*pkeyp == NULL) {
if ((pk=EVP_PKEY_new()) == NULL) {
abort();
return(0);
}
} else {
@@ -102,7 +101,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
abort();
goto err;
}
+3 -2
View File
@@ -11,6 +11,7 @@
#import "AppDelegate.h"
#import "Host.h"
#import "App.h"
#import "TemporaryApp.h"
@interface DataManager : NSObject
@@ -22,7 +23,7 @@
- (void) saveData;
- (Host*) createHost;
- (void) removeHost:(Host*)host;
- (App*) createApp;
- (void) removeApp:(App*)app;
- (App*) addAppFromTemporaryApp:(TemporaryApp*)tempApp;
- (void) removeAppFromHost:(App*)app;
@end
+53 -17
View File
@@ -7,9 +7,18 @@
//
#import "DataManager.h"
#import "TemporaryApp.h"
@implementation DataManager
+ (NSObject *)databaseLock {
static NSObject *lock = nil;
if (lock == nil) {
lock = [[NSObject alloc] init];
}
return lock;
}
- (id) init {
self = [super init];
self.appDelegate = [[UIApplication sharedApplication] delegate];
@@ -57,38 +66,65 @@
}
- (void) saveData {
NSError* error;
if (![[self.appDelegate managedObjectContext] save:&error]) {
Log(LOG_E, @"Unable to save hosts to database: %@", error);
@synchronized([DataManager databaseLock]) {
NSError* error;
if (![[self.appDelegate managedObjectContext] save:&error]) {
Log(LOG_E, @"Unable to save hosts to database: %@", error);
}
[self.appDelegate saveContext];
}
[self.appDelegate saveContext];
}
- (NSArray*) retrieveHosts {
return [self fetchRecords:@"Host"];
}
- (App*) createApp {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]];
return [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
- (App*) addAppFromTemporaryApp:(TemporaryApp*)tempApp {
App* managedApp;
@synchronized([DataManager databaseLock]) {
NSEntityDescription* entity = [NSEntityDescription entityForName:@"App" inManagedObjectContext:[self.appDelegate managedObjectContext]];
managedApp = [[App alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
assert(tempApp.host != nil);
managedApp.id = tempApp.id;
managedApp.image = tempApp.image;
managedApp.name = tempApp.name;
managedApp.isRunning = tempApp.isRunning;
managedApp.host = tempApp.host;
[managedApp.host addAppListObject:managedApp];
}
return managedApp;
}
- (void) removeApp:(App*)app {
[[self.appDelegate managedObjectContext] deleteObject:app];
- (void) removeAppFromHost:(App*)app {
@synchronized([DataManager databaseLock]) {
assert(app.host != nil);
[app.host removeAppListObject:app];
[[self.appDelegate managedObjectContext] deleteObject:app];
}
}
- (NSArray*) fetchRecords:(NSString*)entityName {
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self.appDelegate managedObjectContext]];
[fetchRequest setEntity:entity];
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
NSArray* fetchedRecords;
NSError* error;
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
//TODO: handle errors
@synchronized([DataManager databaseLock]) {
NSFetchRequest* fetchRequest = [[NSFetchRequest alloc] init];
NSEntityDescription* entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:[self.appDelegate managedObjectContext]];
[fetchRequest setEntity:entity];
[fetchRequest setAffectedStores:[NSArray arrayWithObjects:[[self.appDelegate persistentStoreCoordinator] persistentStoreForURL:[self.appDelegate getStoreURL]], nil]];
NSError* error;
fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
//TODO: handle errors
}
return fetchedRecords;
}
@end
+1
View File
@@ -17,5 +17,6 @@
@property (nonatomic, retain) NSNumber * height;
@property (nonatomic, retain) NSNumber * width;
@property (nonatomic, retain) NSNumber * onscreenControls;
@property (nonatomic, retain) NSString * uniqueId;
@end
+1
View File
@@ -16,5 +16,6 @@
@dynamic height;
@dynamic width;
@dynamic onscreenControls;
@dynamic uniqueId;
@end
+20
View File
@@ -0,0 +1,20 @@
//
// TemporaryApp.h
// Moonlight
//
// Created by Cameron Gutman on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "Host.h"
@interface TemporaryApp : NSObject
@property (nullable, nonatomic, retain) NSString *id;
@property (nullable, nonatomic, retain) NSData *image;
@property (nullable, nonatomic, retain) NSString *name;
@property (nonatomic) BOOL isRunning;
@property (nullable, nonatomic, retain) Host *host;
@end
+13
View File
@@ -0,0 +1,13 @@
//
// TemporaryApp.m
// Moonlight
//
// Created by Cameron Gutman on 9/30/15.
// Copyright © 2015 Moonlight Stream. All rights reserved.
//
#import "TemporaryApp.h"
@implementation TemporaryApp
@end
+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "a_button_40x40@1x.png"
"filename" : "a_button_80x80@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "a_button_80x80@2x.png"
"filename" : "a_button_120x120@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "a_button_120x120@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "b_button_40x40@1x.png"
"filename" : "b_button_80x80@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "b_button_80x80@2x.png"
"filename" : "b_button_120x120@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "b_button_120x120@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

+6
View File
@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "down_31x38@1x.png"
"filename" : "down_61x75@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "down_61x75@2x.png"
"filename" : "down_93x114@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "down_93x114@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "left_38x31@1x.png"
"filename" : "left_76x61@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "left_76x61@2x.png"
"filename" : "left_114x92@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "left_114x92@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

@@ -0,0 +1,23 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "pull-arrow-light-14x31@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "pull-arrow-light-28x61@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "pull-arrow-light-42x92@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 901 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 812 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "right_38x31@1x.png"
"filename" : "right_75x61@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "right_75x61@2x.png"
"filename" : "right_114x93@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "right_114x93@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "up_31x39@1x.png"
"filename" : "up_61x76@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "up_61x76@2x.png"
"filename" : "up_93x116@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "up_93x116@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "x_button_40x40@1x.png"
"filename" : "x_button_80x80@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "x_button_80x80@2x.png"
"filename" : "x_button_120x120@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "x_button_120x120@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.3 KiB

+5 -6
View File
@@ -2,18 +2,17 @@
"images" : [
{
"idiom" : "universal",
"scale" : "1x",
"filename" : "y_button_40x40@1x.png"
"filename" : "y_button_80x80@2x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x",
"filename" : "y_button_80x80@2x.png"
"filename" : "y_button_120x120@3x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x",
"filename" : "y_button_120x120@3x.png"
"scale" : "3x"
}
],
"info" : {
Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

+244 -61
View File
@@ -63,25 +63,30 @@
BOOL l3Set;
BOOL r3Set;
BOOL _iPad;
CGRect _controlArea;
UIView* _view;
OnScreenControlsLevel _level;
ControllerSupport *_controllerSupport;
Controller *_controller;
id<EdgeDetectionDelegate> _edgeDelegate;
NSMutableArray* _deadTouches;
}
static const float EDGE_WIDTH = .1;
static const float EDGE_WIDTH = .05;
//static const float BUTTON_SIZE = 50;
static const float BUTTON_DIST = 20;
static float BUTTON_CENTER_X;
static float BUTTON_CENTER_Y;
static const float D_PAD_DIST = 15;
static const float D_PAD_DIST = 10;
static float D_PAD_CENTER_X;
static float D_PAD_CENTER_Y;
static const float DEAD_ZONE_PADDING = 15;
static const double STICK_CLICK_RATE = 100;
static const float STICK_DEAD_ZONE = .1;
static float STICK_INNER_SIZE;
@@ -117,6 +122,21 @@ static float L3_Y;
_controller = [[Controller alloc] init];
_controller.playerIndex = 0;
_edgeDelegate = swipeDelegate;
_deadTouches = [[NSMutableArray alloc] init];
_iPad = (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
_controlArea = CGRectMake(0, 0, _view.frame.size.width, _view.frame.size.height);
if (_iPad)
{
// Cut down the control area on an iPad so the controls are more reachable
_controlArea.size.height = _view.frame.size.height / 2.0;
_controlArea.origin.y = _view.frame.size.height - _controlArea.size.height;
}
else
{
_controlArea.origin.x = _controlArea.size.width * EDGE_WIDTH;
_controlArea.size.width -= _controlArea.origin.x * 2;
}
_aButton = [CALayer layer];
_bButton = [CALayer layer];
@@ -139,7 +159,7 @@ static float L3_Y;
_leftStick = [CALayer layer];
_rightStick = [CALayer layer];
_edge = [CALayer layer];
[self setupEdgeDetection];
return self;
@@ -167,10 +187,10 @@ static float L3_Y;
[self hideButtons];
[self hideBumpers];
[self hideL3R3];
[self drawTriggers];
[self drawStartSelect];
[self drawSticks];
[self drawL3R3];
break;
case OnScreenControlsLevelAutoGCExtendedGamepad:
// GCExtendedGamepad is missing R3, L3, and select
@@ -219,8 +239,8 @@ static float L3_Y;
// Start with the default complex layout
[self setupComplexControls];
START_Y = _view.frame.size.height * .9;
SELECT_Y = _view.frame.size.height * .9;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
}
// For GCGamepad controls we move triggers, start, and select
@@ -229,7 +249,42 @@ static float L3_Y;
// Start with the default complex layout
[self setupComplexControls];
// TODO
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
if (_iPad) {
START_X = _controlArea.size.width * .75 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .25 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
// The analog sticks are kept closer to the sides on iPad
LS_CENTER_X = _controlArea.size.width * .18 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .82 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
} else {
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
LS_CENTER_X = _controlArea.size.width * .25 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .75 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
}
// For simple controls we move the triggers and buttons to the bottom
@@ -237,46 +292,59 @@ static float L3_Y;
// Start with the default complex layout
[self setupComplexControls];
START_Y = _view.frame.size.height * .9;
SELECT_Y = _view.frame.size.height * .9;
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .4 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L1_Y = _view.frame.size.height * .7;
L2_Y = _view.frame.size.height * .9;
L2_X = _view.frame.size.width * .1;
R1_Y = _view.frame.size.height * .7;
R2_Y = _view.frame.size.height * .9;
R2_X = _view.frame.size.width * .9;
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
}
- (void) setupComplexControls
{
D_PAD_CENTER_X = _view.frame.size.width * .15;
D_PAD_CENTER_Y = _view.frame.size.height * .55;
BUTTON_CENTER_X = _view.frame.size.width * .85;
BUTTON_CENTER_Y = _view.frame.size.height * .55;
D_PAD_CENTER_X = _controlArea.size.width * .1 + _controlArea.origin.x;
D_PAD_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
BUTTON_CENTER_X = _controlArea.size.width * .9 + _controlArea.origin.x;
BUTTON_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
LS_CENTER_X = _view.frame.size.width * .35;
LS_CENTER_Y = _view.frame.size.height * .75;
RS_CENTER_X = _view.frame.size.width * .65;
RS_CENTER_Y = _view.frame.size.height * .75;
if (_iPad)
{
// The analog sticks are kept closer to the sides on iPad
LS_CENTER_X = _controlArea.size.width * .22 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .77 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
else
{
LS_CENTER_X = _controlArea.size.width * .35 + _controlArea.origin.x;
LS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
RS_CENTER_X = _controlArea.size.width * .65 + _controlArea.origin.x;
RS_CENTER_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
START_X = _view.frame.size.width * .6;
START_Y = _view.frame.size.height * .1;
SELECT_X = _view.frame.size.width * .4;
SELECT_Y = _view.frame.size.height * .1;
START_X = _controlArea.size.width * .9 + _controlArea.origin.x;
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
SELECT_X = _controlArea.size.width * .1 + _controlArea.origin.x;
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
L1_X = _view.frame.size.width * .15;
L1_Y = _view.frame.size.height * .27;
L2_X = _view.frame.size.width * .15;
L2_Y = _view.frame.size.height * .1;
R1_X = _view.frame.size.width * .85;
R1_Y = _view.frame.size.height * .27;
R2_X = _view.frame.size.width * .85;
R2_Y = _view.frame.size.height * .1;
L3_X = _view.frame.size.width * .25;
L3_Y = _view.frame.size.height * .75;
R3_X = _view.frame.size.width * .75;
R3_Y = _view.frame.size.height * .75;
L1_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
L2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
R1_X = _controlArea.size.width * .9 + _controlArea.origin.x;
R1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
R2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
L3_X = _controlArea.size.width * .25 + _controlArea.origin.x;
L3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
R3_X = _controlArea.size.width * .75 + _controlArea.origin.x;
R3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
}
- (void) drawButtons {
@@ -285,43 +353,43 @@ static float L3_Y;
_aButton.contents = (id) aButtonImage.CGImage;
_aButton.frame = CGRectMake(BUTTON_CENTER_X - aButtonImage.size.width / 2, BUTTON_CENTER_Y + BUTTON_DIST, aButtonImage.size.width, aButtonImage.size.height);
[_view.layer addSublayer:_aButton];
// create B button
UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
_bButton.frame = CGRectMake(BUTTON_CENTER_X + BUTTON_DIST, BUTTON_CENTER_Y - bButtonImage.size.height / 2, bButtonImage.size.width, bButtonImage.size.height);
_bButton.contents = (id) bButtonImage.CGImage;
[_view.layer addSublayer:_bButton];
// create X Button
UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
_xButton.frame = CGRectMake(BUTTON_CENTER_X - BUTTON_DIST - xButtonImage.size.width, BUTTON_CENTER_Y - xButtonImage.size.height/ 2, xButtonImage.size.width, xButtonImage.size.height);
_xButton.contents = (id) xButtonImage.CGImage;
[_view.layer addSublayer:_xButton];
// create Y Button
UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
_yButton.frame = CGRectMake(BUTTON_CENTER_X - yButtonImage.size.width / 2, BUTTON_CENTER_Y - BUTTON_DIST - yButtonImage.size.height, yButtonImage.size.width, yButtonImage.size.height);
_yButton.contents = (id) yButtonImage.CGImage;
[_view.layer addSublayer:_yButton];
// create Down button
UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
_downButton.frame = CGRectMake(D_PAD_CENTER_X - downButtonImage.size.width / 2, D_PAD_CENTER_Y + D_PAD_DIST, downButtonImage.size.width, downButtonImage.size.height);
_downButton.contents = (id) downButtonImage.CGImage;
[_view.layer addSublayer:_downButton];
// create Right button
UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
_rightButton.frame = CGRectMake(D_PAD_CENTER_X + D_PAD_DIST, D_PAD_CENTER_Y - rightButtonImage.size.height / 2, rightButtonImage.size.width, rightButtonImage.size.height);
_rightButton.contents = (id) rightButtonImage.CGImage;
[_view.layer addSublayer:_rightButton];
// create Up button
UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
_upButton.frame = CGRectMake(D_PAD_CENTER_X - upButtonImage.size.width / 2, D_PAD_CENTER_Y - D_PAD_DIST - upButtonImage.size.height, upButtonImage.size.width, upButtonImage.size.height);
_upButton.contents = (id) upButtonImage.CGImage;
[_view.layer addSublayer:_upButton];
// create Left button
UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
_leftButton.frame = CGRectMake(D_PAD_CENTER_X - D_PAD_DIST - leftButtonImage.size.width, D_PAD_CENTER_Y - leftButtonImage.size.height / 2, leftButtonImage.size.width, leftButtonImage.size.height);
@@ -335,7 +403,7 @@ static float L3_Y;
_startButton.frame = CGRectMake(START_X - startButtonImage.size.width / 2, START_Y - startButtonImage.size.height / 2, startButtonImage.size.width, startButtonImage.size.height);
_startButton.contents = (id) startButtonImage.CGImage;
[_view.layer addSublayer:_startButton];
// create Select button
UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
_selectButton.frame = CGRectMake(SELECT_X - selectButtonImage.size.width / 2, SELECT_Y - selectButtonImage.size.height / 2, selectButtonImage.size.width, selectButtonImage.size.height);
@@ -382,7 +450,7 @@ static float L3_Y;
_leftStick.frame = CGRectMake(LS_CENTER_X - leftStickImage.size.width / 2, LS_CENTER_Y - leftStickImage.size.height / 2, leftStickImage.size.width, leftStickImage.size.height);
_leftStick.contents = (id) leftStickImage.CGImage;
[_view.layer addSublayer:_leftStick];
// create right analog stick
UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
_rightStickBackground.frame = CGRectMake(RS_CENTER_X - rightStickBgImage.size.width / 2, RS_CENTER_Y - rightStickBgImage.size.height / 2, rightStickBgImage.size.width, rightStickBgImage.size.height);
@@ -463,7 +531,7 @@ static float L3_Y;
float lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
for (UITouch* touch in touches) {
CGPoint touchLocation = [touch locationInView:_view];
float xLoc = touchLocation.x;
@@ -473,34 +541,34 @@ static float L3_Y;
if (xLoc < lsMinX) xLoc = lsMinX;
if (yLoc > lsMaxY) yLoc = lsMaxY;
if (yLoc < lsMinY) yLoc = lsMinY;
_leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
float xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X);
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true;
} else if (touch == _rsTouch) {
if (xLoc > rsMaxX) xLoc = rsMaxX;
if (xLoc < rsMinX) xLoc = rsMinX;
if (yLoc > rsMaxY) yLoc = rsMaxY;
if (yLoc < rsMinY) yLoc = rsMinY;
_rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
float xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X);
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
updated = true;
} else if (touch == _aTouch) {
buttonTouch = true;
@@ -535,11 +603,14 @@ static float L3_Y;
} else if (touch == _r3Touch) {
buttonTouch = true;
}
if ([_deadTouches containsObject:touch]) {
updated = true;
}
}
if (updated) {
[_controllerSupport updateFinished:_controller];
}
return updated || buttonTouch;
return updated || buttonTouch;
}
- (BOOL)handleTouchDownEvent:touches {
@@ -653,6 +724,10 @@ static float L3_Y;
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
_edgeTouch = touch;
}
if (!updated && !stickTouch && [self isInDeadZone:touch]) {
[_deadTouches addObject:touch];
updated = true;
}
}
if (updated) {
[_controllerSupport updateFinished:_controller];
@@ -744,15 +819,123 @@ static float L3_Y;
touched = true;
} else if (touch == _edgeTouch) {
_edgeTouch = nil;
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) {
if ([touch locationInView:_view].x >= _view.frame.size.width / 4) {
[_edgeDelegate edgeSwiped];
}
}
if ([_deadTouches containsObject:touch]) {
[_deadTouches removeObject:touch];
updated = true;
}
}
if (updated) {
[_controllerSupport updateFinished:_controller];
}
return updated || touched;
}
- (BOOL) isInDeadZone:(UITouch*) touch {
switch (_level) {
case OnScreenControlsLevelFull:
return [self isDpadDeadZone:touch]
|| [self isAbxyDeadZone:touch]
|| [self isTriggerDeadZone:touch]
|| [self isBumperDeadZone:touch]
|| [self isStartSelectDeadZone:touch];
case OnScreenControlsLevelSimple:
return [self isTriggerDeadZone:touch]
|| [self isStartSelectDeadZone:touch]
|| [self isL3R3DeadZone:touch];
case OnScreenControlsLevelAutoGCExtendedGamepad:
return [self isL3R3DeadZone:touch]
|| [self isStartSelectDeadZone:touch];
case OnScreenControlsLevelAutoGCGamepad:
return [self isTriggerDeadZone:touch]
|| [self isStartSelectDeadZone:touch];
default:
return false;
}
}
- (BOOL) isDpadDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_upButton.frame.origin.y
endX:_rightButton.frame.origin.x + _rightButton.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isAbxyDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_xButton.frame.origin.x
startY:_yButton.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isBumperDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l2Button.frame.origin.y + _l2Button.frame.size.height
endX:_l1Button.frame.origin.x + _l1Button.frame.size.width
endY:_upButton.frame.origin.y]
|| [self isDeadZone:touch
startX:_r2Button.frame.origin.x
startY:_r2Button.frame.origin.y + _r2Button.frame.size.height
endX:_view.frame.origin.x + _view.frame.size.width
endY:_yButton.frame.origin.y];
}
- (BOOL) isTriggerDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l2Button.frame.origin.y
endX:_l2Button.frame.origin.x + _l2Button.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_r2Button.frame.origin.x
startY:_r2Button.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isL3R3DeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_l3Button.frame.origin.y
endX:_view.frame.origin.x
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_r3Button.frame.origin.x
startY:_r3Button.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isStartSelectDeadZone:(UITouch*) touch {
return [self isDeadZone:touch
startX:_startButton.frame.origin.x
startY:_startButton.frame.origin.y
endX:_view.frame.origin.x + _view.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height]
|| [self isDeadZone:touch
startX:_view.frame.origin.x
startY:_selectButton.frame.origin.y
endX:_selectButton.frame.origin.x + _selectButton.frame.size.width
endY:_view.frame.origin.y + _view.frame.size.height];
}
- (BOOL) isDeadZone:(UITouch*) touch startX:(float)deadZoneStartX startY:(float)deadZoneStartY endX:(float)deadZoneEndX endY:(float)deadZoneEndY {
deadZoneStartX -= DEAD_ZONE_PADDING;
deadZoneStartY -= DEAD_ZONE_PADDING;
deadZoneEndX += DEAD_ZONE_PADDING;
deadZoneEndY += DEAD_ZONE_PADDING;
CGPoint touchLocation = [touch locationInView:_view];
return (touchLocation.x > deadZoneStartX && touchLocation.x < deadZoneEndX
&& touchLocation.y > deadZoneStartY && touchLocation.y < deadZoneEndY);
}
@end
+14 -13
View File
@@ -67,15 +67,16 @@
deltaX *= xDeltaFactor * screenFactor;
deltaY *= yDeltaFactor * screenFactor;
LiSendMouseMoveEvent(deltaX, deltaY);
touchMoved = true;
touchLocation = currentLocation;
if (deltaX != 0 || deltaY != 0) {
LiSendMouseMoveEvent(deltaX, deltaY);
touchMoved = true;
touchLocation = currentLocation;
}
}
} else if ([[event allTouches] count] == 2) {
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
if (touchLocation.y != avgLocation.y) {
LiSendScrollEvent(avgLocation.y - touchLocation.y);
@@ -93,23 +94,23 @@
if (!touchMoved) {
if ([[event allTouches] count] == 2) {
Log(LOG_D, @"Sending right mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
// Wait 100 ms to simulate a real button press
usleep(100 * 1000);
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
} else {
Log(LOG_D, @"Sending left mouse button press");
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
// Wait 100 ms to simulate a real button press
usleep(100 * 1000);
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
}
}
+6 -4
View File
@@ -17,11 +17,11 @@
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>0.9.2</string>
<string>1.0.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2</string>
<string>3</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.games</string>
<key>LSRequiresIPhoneOS</key>
@@ -50,9 +50,9 @@
<array>
<string>armv7</string>
</array>
<key>UIStatusBarHidden</key>
<key>UIRequiresFullScreen</key>
<true/>
<key>UIStatusBarHidden~ipad</key>
<key>UIStatusBarHidden</key>
<true/>
<key>UISupportedInterfaceOrientations</key>
<array>
@@ -64,5 +64,7 @@
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UIViewControllerBasedStatusBarAppearance</key>
<false/>
</dict>
</plist>
@@ -3,6 +3,6 @@
<plist version="1.0">
<dict>
<key>_XCCurrentVersionName</key>
<string>Moonlight v1.0.xcdatamodel</string>
<string>Moonlight v1.0-2.xcdatamodel</string>
</dict>
</plist>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
<entity name="App" representedClassName="App" syncable="YES">
<attribute name="id" attributeType="String" syncable="YES"/>
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="host" maxCount="1" deletionRule="Nullify" destinationEntity="Host" inverseName="appList" inverseEntity="Host" syncable="YES"/>
</entity>
<entity name="Host" representedClassName="Host" syncable="YES">
<attribute name="address" attributeType="String" syncable="YES"/>
<attribute name="externalAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="localAddress" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="mac" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="name" attributeType="String" syncable="YES"/>
<attribute name="pairState" optional="YES" attributeType="Integer 32" defaultValueString="0" syncable="YES"/>
<attribute name="uuid" optional="YES" attributeType="String" syncable="YES"/>
<relationship name="appList" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="App" inverseName="host" inverseEntity="App" syncable="YES"/>
</entity>
<entity name="Settings" representedClassName="Settings" syncable="YES">
<attribute name="bitrate" attributeType="Integer 32" defaultValueString="10000" syncable="YES"/>
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
<attribute name="uniqueId" attributeType="String" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
</entity>
<elements>
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
</elements>
</model>
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="8118.17" systemVersion="15A204h" minimumToolsVersion="Automatic">
<model userDefinedModelVersionIdentifier="" type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="9057" systemVersion="15B42" minimumToolsVersion="Automatic">
<entity name="App" representedClassName="App" syncable="YES">
<attribute name="id" attributeType="String" syncable="YES"/>
<attribute name="image" optional="YES" attributeType="Binary" allowsExternalBinaryDataStorage="YES" syncable="YES"/>
@@ -21,11 +21,12 @@
<attribute name="framerate" attributeType="Integer 32" defaultValueString="60" syncable="YES"/>
<attribute name="height" attributeType="Integer 32" defaultValueString="720" syncable="YES"/>
<attribute name="onscreenControls" attributeType="Integer 32" defaultValueString="1" syncable="YES"/>
<attribute name="uniqueId" optional="YES" attributeType="String" syncable="YES"/>
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" syncable="YES"/>
</entity>
<elements>
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
<element name="Host" positionX="0" positionY="0" width="128" height="163"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="120"/>
<element name="Settings" positionX="0" positionY="0" width="128" height="135"/>
</elements>
</model>
+2 -1
View File
@@ -11,6 +11,7 @@
#import "CryptoManager.h"
#import "AppAssetResponse.h"
#import "HttpRequest.h"
#import "IdManager.h"
@implementation AppAssetRetriever
static const double RETRY_DELAY = 2; // seconds
@@ -21,7 +22,7 @@ static const int MAX_ATTEMPTS = 5;
int attempts = 0;
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
+2 -3
View File
@@ -7,7 +7,7 @@
//
#import "AppListResponse.h"
#import "App.h"
#import "TemporaryApp.h"
#import "DataManager.h"
#import <libxml2/libxml/xmlreader.h>
@@ -60,7 +60,6 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
self.statusMessage = statusMsg;
node = node->children;
DataManager* dataMan = [[DataManager alloc] init];
while (node != NULL) {
//Log(LOG_D, @"node: %s", node->name);
@@ -96,7 +95,7 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
appInfoNode = appInfoNode->next;
}
if (appId != nil) {
App* app = [dataMan createApp];
TemporaryApp* app = [[TemporaryApp alloc] init];
app.name = appName;
app.id = appId;
app.isRunning = appIsRunning;
+19 -3
View File
@@ -13,6 +13,7 @@
#import "DataManager.h"
#import "DiscoveryWorker.h"
#import "ServerInfoResponse.h"
#import "IdManager.h"
@implementation DiscoveryManager {
NSMutableArray* _hostQueue;
@@ -27,14 +28,29 @@
- (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback {
self = [super init];
_hostQueue = [NSMutableArray arrayWithArray:hosts];
// Using addHostToDiscovery ensures no duplicates
// will make it into the list from the database
_callback = callback;
shouldDiscover = NO;
_hostQueue = [NSMutableArray array];
DataManager* dataMan = [[DataManager alloc] init];
for (Host* host in hosts)
{
if (![self addHostToDiscovery:host])
{
// Remove the duplicate host from the database
[dataMan removeHost:host];
}
}
[dataMan saveData];
[_callback updateAllHosts:_hostQueue];
_opQueue = [[NSOperationQueue alloc] init];
_mdnsMan = [[MDNSManager alloc] initWithCallback:self];
[CryptoManager generateKeyPairUsingSSl];
_uniqueId = [CryptoManager getUniqueID];
_uniqueId = [IdManager getUniqueId];
_cert = [CryptoManager readCertFromFile];
shouldDiscover = NO;
return self;
}
+16 -7
View File
@@ -65,11 +65,16 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
}
void ArInit(void)
void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
{
int err;
opusDecoder = opus_decoder_create(48000, 2, &err);
// We only support stereo for now
assert(audioConfiguration == AUDIO_CONFIGURATION_STEREO);
opusDecoder = opus_decoder_create(opusConfig->sampleRate,
opusConfig->channelCount,
&err);
audioLock = [[NSLock alloc] init];
@@ -77,9 +82,9 @@ void ArInit(void)
NSError *audioSessionError = nil;
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
[audioSession setPreferredSampleRate:48000.0 error:&audioSessionError];
[audioSession setPreferredSampleRate:opusConfig->sampleRate error:&audioSessionError];
[audioSession setCategory: AVAudioSessionCategoryPlayback error: &audioSessionError];
[audioSession setPreferredOutputNumberOfChannels:2 error:&audioSessionError];
[audioSession setPreferredOutputNumberOfChannels:opusConfig->channelCount error:&audioSessionError];
[audioSession setPreferredIOBufferDuration:0.005 error:&audioSessionError];
[audioSession setActive: YES error: &audioSessionError];
@@ -99,11 +104,11 @@ void ArInit(void)
}
AudioStreamBasicDescription audioFormat = {0};
audioFormat.mSampleRate = 48000;
audioFormat.mSampleRate = opusConfig->sampleRate;
audioFormat.mBitsPerChannel = 16;
audioFormat.mFormatID = kAudioFormatLinearPCM;
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
audioFormat.mChannelsPerFrame = 2;
audioFormat.mChannelsPerFrame = opusConfig->channelCount;
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
@@ -280,6 +285,8 @@ void ClDisplayTransientMessage(char* message)
renderer = myRenderer;
_callbacks = callbacks;
_serverMajorVersion = serverMajorVersion;
LiInitializeStreamConfiguration(&_streamConfig);
_streamConfig.width = config.width;
_streamConfig.height = config.height;
_streamConfig.fps = config.frameRate;
@@ -293,13 +300,15 @@ void ClDisplayTransientMessage(char* message)
int riKeyId = htonl(config.riKeyId);
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
memset(&_drCallbacks, 0, sizeof(_drCallbacks));
LiInitializeVideoCallbacks(&_drCallbacks);
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
LiInitializeAudioCallbacks(&_arCallbacks);
_arCallbacks.init = ArInit;
_arCallbacks.cleanup = ArCleanup;
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
LiInitializeConnectionCallbacks(&_clCallbacks);
_clCallbacks.stageStarting = ClStageStarting;
_clCallbacks.stageComplete = ClStageComplete;
_clCallbacks.stageFailed = ClStageFailed;
+2 -1
View File
@@ -15,6 +15,7 @@
#import "ServerInfoResponse.h"
#import "HttpResponse.h"
#import "HttpRequest.h"
#import "IdManager.h"
@implementation StreamManager {
StreamConfiguration* _config;
@@ -36,7 +37,7 @@
- (void)main {
[CryptoManager generateKeyPairUsingSSl];
NSString* uniqueId = [CryptoManager getUniqueID];
NSString* uniqueId = [IdManager getUniqueId];
NSData* cert = [CryptoManager readCertFromFile];
HttpManager* hMan = [[HttpManager alloc] initWithHost:_config.host
@@ -22,6 +22,9 @@
#import "ServerInfoResponse.h"
#import "StreamFrameViewController.h"
#import "LoadingFrameViewController.h"
#import "ComputerScrollView.h"
#import "TemporaryApp.h"
#import "IdManager.h"
@implementation MainFrameViewController {
NSOperationQueue* _opQueue;
@@ -140,10 +143,11 @@ static NSMutableSet* hostList;
- (void) mergeAppLists:(NSArray*) newList forHost:(Host*)host {
DataManager* database = [[DataManager alloc] init];
for (App* app in newList) {
for (TemporaryApp* app in newList) {
BOOL appAlreadyInList = NO;
for (App* savedApp in host.appList) {
if ([app.id isEqualToString:savedApp.id]) {
savedApp.name = app.name;
savedApp.isRunning = app.isRunning;
appAlreadyInList = YES;
break;
@@ -151,25 +155,33 @@ static NSMutableSet* hostList;
}
if (!appAlreadyInList) {
app.host = host;
[host addAppListObject:app];
} else {
[database removeApp:app];
[database addAppFromTemporaryApp:app];
}
}
for (App* app in host.appList) {
BOOL appWasRemoved = YES;
for (App* mergedApp in newList) {
if ([mergedApp.id isEqualToString:app.id]) {
appWasRemoved = NO;
BOOL appWasRemoved;
do {
appWasRemoved = NO;
for (App* app in host.appList) {
appWasRemoved = YES;
for (App* mergedApp in newList) {
if ([mergedApp.id isEqualToString:app.id]) {
appWasRemoved = NO;
break;
}
}
if (appWasRemoved) {
// Removing the app mutates the list we're iterating (which isn't legal).
// We need to jump out of this loop and restart enumeration.
[database removeAppFromHost:app];
break;
}
}
if (appWasRemoved) {
[host removeAppListObject:app];
[database removeApp:app];
}
}
// Keep looping until the list is no longer being mutated
} while (appWasRemoved);
[database saveData];
}
@@ -477,7 +489,7 @@ static NSMutableSet* hostList;
// Set up crypto
[CryptoManager generateKeyPairUsingSSl];
_uniqueId = [CryptoManager getUniqueID];
_uniqueId = [IdManager getUniqueId];
_cert = [CryptoManager readCertFromFile];
_appManager = [[AppAssetManager alloc] initWithCallback:self];
@@ -490,9 +502,24 @@ static NSMutableSet* hostList;
[self setAutomaticallyAdjustsScrollViewInsets:NO];
hostScrollView = [[UIScrollView alloc] init];
hostScrollView = [[ComputerScrollView alloc] init];
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];
hostScrollView.delaysContentTouches = NO;
UIButton* pullArrow = [[UIButton alloc] init];
[pullArrow setImage:[UIImage imageNamed:@"PullArrow"] forState:UIControlStateNormal];
[pullArrow sizeToFit];
pullArrow.frame = CGRectMake(0,
self.collectionView.frame.size.height / 2 - pullArrow.frame.size.height / 2 - self.navigationController.navigationBar.frame.size.height,
pullArrow.frame.size.width,
pullArrow.frame.size.height);
[self.view addSubview:pullArrow];
self.collectionView.delaysContentTouches = NO;
self.collectionView.allowsMultipleSelection = NO;
self.collectionView.multipleTouchEnabled = NO;
[self retrieveSavedHosts];
_discMan = [[DiscoveryManager alloc] initWithHosts:[hostList allObjects] andCallback:self];
@@ -609,6 +636,7 @@ static NSMutableSet* hostList;
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
App* app = _sortedAppList[indexPath.row];
UIAppView* appView = [[UIAppView alloc] initWithApp:app andCallback:self];
[appView updateAppImage];
@@ -621,7 +649,19 @@ static NSMutableSet* hostList;
[cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
[cell addSubview:appView];
UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:cell.bounds];
cell.layer.masksToBounds = NO;
cell.layer.shadowColor = [UIColor blackColor].CGColor;
cell.layer.shadowOffset = CGSizeMake(1.0f, 5.0f);
cell.layer.shadowOpacity = 0.5f;
cell.layer.shadowPath = shadowPath.CGPath;
cell.layer.borderColor = [[UIColor colorWithRed:0 green:0 blue:0 alpha:0.3f] CGColor];
cell.layer.borderWidth = 1;
cell.exclusiveTouch = YES;
return cell;
}
@@ -33,7 +33,7 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
} else if ([currentSettings.height integerValue] == 1080) {
resolution = 1;
} else {
resolution = 2;
resolution = 0;
}
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
@@ -58,22 +58,8 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
- (void) saveSettings {
DataManager* dataMan = [[DataManager alloc] init];
NSInteger framerate = [self.framerateSelector selectedSegmentIndex] == 0 ? 30 : 60;
NSInteger height;
NSInteger width;
if ([self.resolutionSelector selectedSegmentIndex] == 2) {
// Get screen native resolution
height = [UIScreen mainScreen].bounds.size.height * [UIScreen mainScreen].scale;
width = [UIScreen mainScreen].bounds.size.width * [UIScreen mainScreen].scale;
UIAlertController *alertResolution = [UIAlertController alertControllerWithTitle:@"Native resolution" message:[NSString stringWithFormat:@"You must select the following resolution in the game settings: %lix%li", (long)width, (long)height] preferredStyle:UIAlertControllerStyleAlert];
[alertResolution addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alertResolution animated:YES completion:nil];
}
else
{
height = [self.resolutionSelector selectedSegmentIndex] == 0 ? 720 : 1080;
width = height == 720 ? 1280 : 1920;
}
NSInteger height = [self.resolutionSelector selectedSegmentIndex] == 0 ? 720 : 1080;
NSInteger width = height == 720 ? 1280 : 1920;
NSInteger onscreenControls = [self.onscreenControlSelector selectedSegmentIndex];
[dataMan saveSettingsWithBitrate:_bitrate framerate:framerate height:height width:width onscreenControls:onscreenControls];
}
@@ -114,6 +114,8 @@
}]];
[self presentViewController:alert animated:YES completion:nil];
});
[_streamMan stopStreamInternal];
}
- (void) launchFailed:(NSString*)message {
+31 -5
View File
@@ -3,10 +3,11 @@
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objectVersion = 47;
objects = {
/* Begin PBXBuildFile section */
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */ = {isa = PBXBuildFile; fileRef = 9832D1351BBCD5C50036EF48 /* TemporaryApp.m */; };
987140041B04542F00AB57D5 /* libmoonlight-common.a in Frameworks */ = {isa = PBXBuildFile; fileRef = FB1E43101AE8B0F200AFF679 /* libmoonlight-common.a */; };
9E5D600B1A5A5A3900689918 /* Apache License.txt in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF81A5A5A3900689918 /* Apache License.txt */; };
9E5D600C1A5A5A3900689918 /* Roboto-Black.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */; };
@@ -15,6 +16,8 @@
9E5D60131A5A5A3900689918 /* Roboto-Medium.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */; };
9E5D60151A5A5A3900689918 /* Roboto-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */; };
9E5D60161A5A5A3900689918 /* Roboto-Thin.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */; };
FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */; };
FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */; };
FB290CF219B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; };
FB290CF419B2C406004C83CF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF319B2C406004C83CF /* CoreGraphics.framework */; };
FB290CF619B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
@@ -34,6 +37,7 @@
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */; };
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB53E1421BE5DC4400CD6ECE /* IdManager.m */; };
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
@@ -91,6 +95,8 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TemporaryApp.h; path = Database/TemporaryApp.h; sourceTree = "<group>"; };
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TemporaryApp.m; path = Database/TemporaryApp.m; sourceTree = "<group>"; };
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = "moonlight-common.xcodeproj"; path = "limelight-common-c/moonlight-common.xcodeproj"; sourceTree = "<group>"; };
9E5D5FF81A5A5A3900689918 /* Apache License.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "Apache License.txt"; sourceTree = "<group>"; };
9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; };
@@ -99,6 +105,10 @@
9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; };
9E5D60021A5A5A3900689918 /* Roboto-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Regular.ttf"; sourceTree = "<group>"; };
9E5D60031A5A5A3900689918 /* Roboto-Thin.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Thin.ttf"; sourceTree = "<group>"; };
FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComputerScrollView.h; sourceTree = "<group>"; };
FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ComputerScrollView.m; sourceTree = "<group>"; };
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppCollectionView.h; sourceTree = "<group>"; };
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppCollectionView.m; sourceTree = "<group>"; };
FB290CEE19B2C406004C83CF /* Moonlight.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Moonlight.app; sourceTree = BUILT_PRODUCTS_DIR; };
FB290CF119B2C406004C83CF /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; };
FB290CF319B2C406004C83CF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
@@ -127,6 +137,9 @@
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
FB4A23B61A9D3637004D2EF2 /* LoadingFrameViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoadingFrameViewController.h; sourceTree = "<group>"; };
FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LoadingFrameViewController.m; sourceTree = "<group>"; };
FB53E1411BE5DC4400CD6ECE /* IdManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IdManager.h; sourceTree = "<group>"; };
FB53E1421BE5DC4400CD6ECE /* IdManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IdManager.m; sourceTree = "<group>"; };
FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.0-2.xcdatamodel"; sourceTree = "<group>"; };
FB6549541A57907E001C8F39 /* DiscoveryWorker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DiscoveryWorker.h; sourceTree = "<group>"; };
FB6549551A57907E001C8F39 /* DiscoveryWorker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DiscoveryWorker.m; sourceTree = "<group>"; };
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
@@ -397,6 +410,10 @@
FB89463719F6473800339C8A /* Launch Screen.xib */,
FB290D0819B2C406004C83CF /* Images.xcassets */,
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */,
FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */,
FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */,
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */,
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */,
);
path = Limelight;
sourceTree = "<group>";
@@ -419,6 +436,8 @@
FB89460619F646E200339C8A /* CryptoManager.m */,
FB89460719F646E200339C8A /* mkcert.c */,
FB89460819F646E200339C8A /* mkcert.h */,
FB53E1411BE5DC4400CD6ECE /* IdManager.h */,
FB53E1421BE5DC4400CD6ECE /* IdManager.m */,
);
path = Crypto;
sourceTree = "<group>";
@@ -712,6 +731,8 @@
FBD3495D1A004412002D2A60 /* Settings.m */,
FBD349601A0089F6002D2A60 /* DataManager.h */,
FBD349611A0089F6002D2A60 /* DataManager.m */,
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */,
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */,
);
name = Database;
sourceTree = "<group>";
@@ -744,7 +765,7 @@
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0700;
ORGANIZATIONNAME = "Limelight Stream";
ORGANIZATIONNAME = "Moonlight Stream";
TargetAttributes = {
FB290CED19B2C406004C83CF = {
DevelopmentTeam = DM46QST4M7;
@@ -752,7 +773,7 @@
};
};
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
compatibilityVersion = "Xcode 3.2";
compatibilityVersion = "Xcode 6.3";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
@@ -821,12 +842,14 @@
FB89462F19F646E200339C8A /* Connection.m in Sources */,
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */,
FB89462919F646E200339C8A /* mkcert.c in Sources */,
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */,
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
FBFCB3311B50B29400089F8A /* Host.m in Sources */,
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */,
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
FB89462C19F646E200339C8A /* HttpManager.m in Sources */,
FB89462D19F646E200339C8A /* MDNSManager.m in Sources */,
@@ -834,7 +857,9 @@
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */,
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */,
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
@@ -986,7 +1011,7 @@
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
ENABLE_BITCODE = NO;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
@@ -1038,12 +1063,13 @@
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
isa = XCVersionGroup;
children = (
FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */,
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */,
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */,
FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */,
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */,
);
currentVersion = FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */;
currentVersion = FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */;
path = Limelight.xcdatamodeld;
sourceTree = "<group>";
versionGroupType = wrapper.xcdatamodel;
+2
View File
@@ -1,5 +1,7 @@
#Moonlight iOS
#### Update 7/16/15: We are not accepting more users into the beta program at this time. However, Moonlight iOS is getting ready to launch on the App Store. To be notified when this happens, [please sign up here](http://eepurl.com/btvkG9) to receive a one-time email notification when it's available to download onto your iOS device.
[Moonlight](https://github.com/moonlight-stream) is an open source implementation of NVIDIA's GameStream, as used by the NVIDIA Shield, but built for iOS. Moonlight iOS allows you to stream your full collection of Steam games from
your powerful desktop computer to your iOS Device.
+30 -8
View File
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="EVd-wq-ego">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15B38b" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" initialViewController="EVd-wq-ego">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies>
<customFonts key="customFonts">
<mutableArray key="Roboto-Regular.ttf">
@@ -13,9 +14,11 @@
<scene sceneID="Me4-Nr-liz">
<objects>
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d" customClass="AppCollectionView">
<rect key="frame" x="0.0" y="64" width="1024" height="704"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
<size key="itemSize" width="150" height="200"/>
@@ -25,13 +28,15 @@
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="fv6-NS-qsK">
<rect key="frame" x="20" y="20" width="150" height="200"/>
<rect key="frame" x="20" y="40" width="150" height="200"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="150" height="200"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<animations/>
</collectionViewCell>
</cells>
<connections>
@@ -42,14 +47,15 @@
<navigationItem key="navigationItem" id="pSu-bl-gL9">
<barButtonItem key="leftBarButtonItem" style="done" id="mSL-ru-nRm">
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="Tiq-VS-Ua5">
<rect key="frame" x="101" y="236" width="109" height="46"/>
<rect key="frame" x="20" y="-1" width="109" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
<state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
</button>
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</barButtonItem>
<barButtonItem key="rightBarButtonItem" title="No Host Selected" id="KDy-JC-2sU">
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -77,6 +83,7 @@
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="lMt-4H-fkV">
<rect key="frame" x="16" y="39" width="151" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -85,11 +92,13 @@
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="JAY-nj-UNz">
<rect key="frame" x="14" y="68" width="213" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aiv-r8-9k2">
<rect key="frame" x="16" y="106" width="79" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -98,6 +107,7 @@
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="pYZ-GR-EwO">
<rect key="frame" x="16" y="171" width="82" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -106,16 +116,17 @@
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="ckc-Dm-8ex">
<rect key="frame" x="16" y="200" width="209" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<segments>
<segment title="720p"/>
<segment title="1080p"/>
<segment title="Native"/>
</segments>
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="LGV-5y-piG">
<rect key="frame" x="16" y="236" width="153" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
@@ -124,6 +135,7 @@
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="qSU-wh-tqA">
<rect key="frame" x="16" y="265" width="209" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<segments>
<segment title="Off"/>
<segment title="Auto"/>
@@ -135,6 +147,7 @@
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="lGK-vl-pdw">
<rect key="frame" x="16" y="135" width="209" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<segments>
<segment title="30 Hz"/>
<segment title="60 Hz"/>
@@ -142,6 +155,7 @@
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl>
</subviews>
<animations/>
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
@@ -164,6 +178,7 @@
<view key="view" contentMode="scaleToFill" id="hGs-BR-t4b">
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
@@ -184,6 +199,8 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" translucent="NO" id="RUe-14-4Ya">
<rect key="frame" x="0.0" y="0.0" width="768" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
</navigationBar>
<connections>
<segue destination="wb7-af-jn8" kind="relationship" relationship="rootViewController" id="nkY-JG-Wki"/>
@@ -204,16 +221,19 @@
<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"/>
<animations/>
</activityIndicatorView>
<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"/>
<animations/>
<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"/>
<animations/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="iUf-9X-GeA"/>
<nil key="simulatedStatusBarMetrics"/>
@@ -241,8 +261,10 @@
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" id="N0D-dj-EuF">
<rect key="frame" x="494" y="365" width="37" height="37"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
</activityIndicatorView>
</subviews>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
+29 -12
View File
@@ -1,7 +1,8 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="8191" systemVersion="15B38b" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" initialViewController="DL0-L5-LOv">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
</dependencies>
<customFonts key="customFonts">
<mutableArray key="Roboto-Regular.ttf">
@@ -13,9 +14,11 @@
<scene sceneID="emz-kO-L7q">
<objects>
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="Rtu-AT-Alw">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" dataMode="prototypes" id="Rtu-AT-Alw" customClass="AppCollectionView">
<rect key="frame" x="0.0" y="64" width="568" height="256"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<animations/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="YcZ-cR-3tK">
<size key="itemSize" width="90" height="120"/>
@@ -25,13 +28,15 @@
</collectionViewFlowLayout>
<cells>
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="Uqv-Di-fzX">
<rect key="frame" x="20" y="20" width="90" height="120"/>
<rect key="frame" x="20" y="40" width="90" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
<rect key="frame" x="0.0" y="0.0" width="90" height="120"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
</view>
<animations/>
</collectionViewCell>
</cells>
<connections>
@@ -43,8 +48,9 @@
<navigationItem key="navigationItem" id="1jn-Sf-Xky">
<barButtonItem key="leftBarButtonItem" style="done" id="zAn-CM-7Yz">
<button key="customView" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="pZ9-ft-T24">
<rect key="frame" x="0.0" y="0.0" width="109" height="46"/>
<rect key="frame" x="20" y="-1" width="109" height="46"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
<state key="normal" title="Moonlight" image="Logo">
<color key="titleColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
@@ -74,6 +80,7 @@
<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"/>
<animations/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
@@ -97,11 +104,13 @@
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="20" minValue="1" maxValue="100" id="3nn-MI-9Xu">
<rect key="frame" x="14" y="49" width="204" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</slider>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Bitrate: 10 Mbps" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="SBv-Wn-LB7">
<rect key="frame" x="16" y="20" width="151" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@@ -109,6 +118,7 @@
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="dLF-qJ-2nY">
<rect key="frame" x="16" y="116" width="200" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<segments>
<segment title="30 Hz"/>
<segment title="60 Hz"/>
@@ -118,6 +128,7 @@
<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="87" width="79" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@@ -125,6 +136,7 @@
<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="152" width="82" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@@ -132,16 +144,17 @@
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="PCM-t4-Sha">
<rect key="frame" x="16" y="181" width="200" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<segments>
<segment title="720p"/>
<segment title="1080p"/>
<segment title="Native"/>
</segments>
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="On-Screen Controls" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="HZT-dd-DuQ">
<rect key="frame" x="16" y="217" width="153" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
@@ -149,6 +162,7 @@
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="WGf-9d-eAm">
<rect key="frame" x="16" y="246" width="200" height="29"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<segments>
<segment title="Off"/>
<segment title="Auto"/>
@@ -158,6 +172,7 @@
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</segmentedControl>
</subviews>
<animations/>
<color key="backgroundColor" red="0.12156862745098039" green="0.12941176470588237" blue="0.14117647058823529" alpha="1" colorSpace="calibratedRGB"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
@@ -181,6 +196,8 @@
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" translucent="NO" id="0ZA-Ec-QgD">
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<animations/>
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
<textAttributes key="titleTextAttributes">
<offsetWrapper key="textShadowOffset" horizontal="0.0" vertical="0.0"/>
</textAttributes>
@@ -204,6 +221,7 @@
<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="149" width="45" height="21"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<animations/>
<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"/>
@@ -211,9 +229,11 @@
<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="121" width="20" height="20"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
<animations/>
</activityIndicatorView>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<animations/>
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
</view>
<navigationItem key="navigationItem" id="8uX-4T-BiC"/>
<nil key="simulatedStatusBarMetrics"/>
@@ -239,8 +259,10 @@
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="oNu-Gu-QeM">
<rect key="frame" x="266" y="141" width="37" height="37"/>
<animations/>
</activityIndicatorView>
</subviews>
<animations/>
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
</view>
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
@@ -256,9 +278,4 @@
<resources>
<image name="Logo" width="32" height="32"/>
</resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>