Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4ba71db7b2 | ||
|
|
c1e6aeb43c | ||
|
|
e3ffb66ef0 | ||
|
|
5daa82b0ba | ||
|
|
a8bcc6afba | ||
|
|
e6aa16ad01 | ||
|
|
ad0705d126 | ||
|
|
2f31f93bf8 | ||
|
|
ea3be613c5 | ||
|
|
b495246f34 | ||
|
|
814470f4bf | ||
|
|
82293a08b6 | ||
|
|
20d66336a7 | ||
|
|
c8441ec9fa | ||
|
|
f72135c227 | ||
|
|
100e6e4ce8 | ||
|
|
ec8be20d62 | ||
|
|
55d48101ef | ||
|
|
c36f4c5f84 | ||
|
|
06289ac4d2 | ||
|
|
e6a2d5d425 | ||
|
|
ea8db9c4ea | ||
|
|
3773e841d1 | ||
|
|
ad1ddd04f3 | ||
|
|
67a8b232b9 | ||
|
|
5293c07fc0 | ||
|
|
e3a42db007 | ||
|
|
3b1462af22 | ||
|
|
74a0c5b1cd | ||
|
|
05a5e4fa64 | ||
|
|
b6445295a7 | ||
|
|
391605ef36 | ||
|
|
695499dea9 | ||
|
|
9ba7f35444 | ||
|
|
37dc00735b | ||
|
|
920cbadc91 | ||
|
|
bc53b4dc32 | ||
|
|
6015c38d17 | ||
|
|
4ea8694a7d | ||
|
|
00f01196fb | ||
|
|
543639c93e | ||
|
|
1da877fed7 | ||
|
|
396b5fc156 | ||
|
|
297dfd4159 | ||
|
|
23e9d48b0d | ||
|
|
9ec650a84f | ||
|
|
90bdbc4ae0 | ||
|
|
dd5f06723b | ||
|
|
55b2871b83 | ||
|
|
c8b13126d0 | ||
|
|
96cfe0b70d | ||
|
|
6dbb938368 | ||
|
|
46fe7a8aed | ||
|
|
3151ac6bf0 | ||
|
|
dc5210f691 | ||
|
|
1f02265003 | ||
|
|
e4af9032e2 | ||
|
|
e8650b2420 | ||
|
|
9c6b718be2 | ||
|
|
8f12114a56 | ||
|
|
dc6ebffab1 | ||
|
|
13e894e9a3 | ||
|
|
4c95773131 | ||
|
|
38776a01e4 | ||
|
|
b2563e534d | ||
|
|
37f25c1f97 | ||
|
|
642085ca32 | ||
|
|
5dee29a21c | ||
|
|
b01d13976b | ||
|
|
ae1c83a011 | ||
|
|
e5f962dc3f | ||
|
|
54dd79d2dd | ||
|
|
935fb6ffe3 | ||
|
|
48d1c1a080 | ||
|
|
2d02ce2a1b | ||
|
|
29fda59a72 | ||
|
|
05f0dfd4f5 | ||
|
|
0bdc5a83f1 | ||
|
|
8688bf1210 | ||
|
|
bf0858d57e | ||
|
|
8d4d391310 | ||
|
|
8fb15336c4 | ||
|
|
883385c42b | ||
|
|
6d1139796e | ||
|
|
e58eb5f56a | ||
|
|
2b0ce49646 | ||
|
|
73364127d2 | ||
|
|
84a986bc88 | ||
|
|
f13051aa31 | ||
|
|
6bb559303b | ||
|
|
b7324f9a44 | ||
|
|
c0b2bbe552 | ||
|
|
8c36cf40fd | ||
|
|
717296269f | ||
|
|
4be29abede | ||
|
|
528af9684e | ||
|
|
ff7a4ef190 | ||
|
|
99a2dbb956 | ||
|
|
280341791a | ||
|
|
1759565920 | ||
|
|
f57fa678f6 | ||
|
|
f8b5b16109 | ||
|
|
005a678089 | ||
|
|
315dd53dcb | ||
|
|
bb24495b3f | ||
|
|
b9f2764990 | ||
|
|
a9a00629b1 | ||
|
|
1223a9013f | ||
|
|
ab019eef0f |
No files matched your search
@@ -1,2 +1,3 @@
|
|||||||
**/xcuserdata/
|
**/xcuserdata/
|
||||||
|
**/Moonlight.xcscmblueprint
|
||||||
Build
|
Build
|
||||||
@@ -31,43 +31,44 @@ do
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
echo "Compiling source for $ARCH in directory $OPUS_DIR"
|
echo "Compiling source for $ARCH in directory $OPUS_DIR"
|
||||||
|
echo "cd $OPUS_DIR"
|
||||||
cd $OPUS_DIR
|
cd $OPUS_DIR
|
||||||
|
|
||||||
DIST_DIR=$DIST_DIR_BASE-$ARCH
|
DIST_DIR=$DIST_DIR_BASE-$ARCH
|
||||||
|
echo "mkdir -p $DIST_DIR"
|
||||||
mkdir -p $DIST_DIR
|
mkdir -p $DIST_DIR
|
||||||
CFLAGS_ARCH=$ARCH
|
CFLAGS_ARCH=$ARCH
|
||||||
case $ARCH in
|
case $ARCH in
|
||||||
armv7)
|
armv7)
|
||||||
EXTRA_FLAGS="--with-pic --enable-fixed-point"
|
EXTRA_FLAGS="--with-pic --enable-fixed-point"
|
||||||
EXTRA_CFLAGS="-mcpu=cortex-a8 -mfpu=neon"
|
EXTRA_CFLAGS="-mcpu=cortex-a8 -mfpu=neon -miphoneos-version-min=7.1"
|
||||||
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
|
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
|
||||||
IOSSDK=iPhoneOS${IOSSDK_VER}
|
IOSSDK=iPhoneOS
|
||||||
;;
|
;;
|
||||||
armv7s)
|
armv7s)
|
||||||
EXTRA_FLAGS="--with-pic --enable-fixed-point"
|
EXTRA_FLAGS="--with-pic --enable-fixed-point"
|
||||||
EXTRA_CFLAGS="-mcpu=cortex-a9 -mfpu=neon -miphoneos-version-min=6.0"
|
EXTRA_CFLAGS="-mcpu=cortex-a9 -mfpu=neon -miphoneos-version-min=7.1"
|
||||||
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
|
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
|
||||||
IOSSDK=iPhoneOS${IOSSDK_VER}
|
IOSSDK=iPhoneOS
|
||||||
;;
|
;;
|
||||||
aarch64)
|
aarch64)
|
||||||
CFLAGS_ARCH="arm64"
|
CFLAGS_ARCH="arm64"
|
||||||
EXTRA_FLAGS="--with-pic --enable-fixed-point"
|
EXTRA_FLAGS="--with-pic --enable-fixed-point"
|
||||||
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
|
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
|
||||||
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
|
PLATFORM="${PLATFORMBASE}/iPhoneOS.platform"
|
||||||
IOSSDK=iPhoneOS${IOSSDK_VER}
|
IOSSDK=iPhoneOS
|
||||||
;;
|
;;
|
||||||
x86_64)
|
x86_64)
|
||||||
EXTRA_FLAGS="--with-pic"
|
EXTRA_FLAGS="--with-pic"
|
||||||
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
|
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
|
||||||
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
|
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
|
||||||
IOSSDK=iPhoneSimulator${IOSSDK_VER}
|
IOSSDK=iPhoneSimulator
|
||||||
;;
|
;;
|
||||||
i386)
|
i386)
|
||||||
EXTRA_FLAGS="--with-pic"
|
EXTRA_FLAGS="--with-pic"
|
||||||
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
|
EXTRA_CFLAGS="-miphoneos-version-min=7.1"
|
||||||
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
|
PLATFORM="${PLATFORMBASE}/iPhoneSimulator.platform"
|
||||||
IOSSDK=iPhoneSimulator${IOSSDK_VER}
|
IOSSDK=iPhoneSimulator
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unsupported architecture ${ARCH}"
|
echo "Unsupported architecture ${ARCH}"
|
||||||
@@ -76,7 +77,7 @@ do
|
|||||||
esac
|
esac
|
||||||
|
|
||||||
echo "Configuring opus for $ARCH..."
|
echo "Configuring opus for $ARCH..."
|
||||||
|
echo "./autogen.sh"
|
||||||
./autogen.sh
|
./autogen.sh
|
||||||
|
|
||||||
CFLAGS="-g -O2 -pipe -arch ${CFLAGS_ARCH} \
|
CFLAGS="-g -O2 -pipe -arch ${CFLAGS_ARCH} \
|
||||||
@@ -86,7 +87,10 @@ do
|
|||||||
LDFLAGS="-arch ${CFLAGS_ARCH} \
|
LDFLAGS="-arch ${CFLAGS_ARCH} \
|
||||||
-isysroot ${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
|
-isysroot ${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
|
||||||
-L${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk/usr/lib"
|
-L${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk/usr/lib"
|
||||||
|
|
||||||
|
echo "CFLAGS=$CFLAGS"
|
||||||
|
echo "LDFLAGS=$LDFLAGS"
|
||||||
|
|
||||||
export CFLAGS
|
export CFLAGS
|
||||||
export LDFLAGS
|
export LDFLAGS
|
||||||
|
|
||||||
@@ -100,7 +104,15 @@ do
|
|||||||
export NM="/usr/bin/nm"
|
export NM="/usr/bin/nm"
|
||||||
export RANLIB="/usr/bin/ranlib"
|
export RANLIB="/usr/bin/ranlib"
|
||||||
export STRIP="/usr/bin/strip"
|
export STRIP="/usr/bin/strip"
|
||||||
|
echo "./configure \
|
||||||
|
--prefix=$DIST_DIR \
|
||||||
|
--host=${ARCH}-apple-darwin \
|
||||||
|
--with-sysroot=${PLATFORM}/Developer/SDKs/${IOSSDK}.sdk \
|
||||||
|
--enable-static=yes \
|
||||||
|
--enable-shared=no \
|
||||||
|
--disable-doc \
|
||||||
|
${EXTRA_FLAGS}"
|
||||||
|
|
||||||
./configure \
|
./configure \
|
||||||
--prefix=$DIST_DIR \
|
--prefix=$DIST_DIR \
|
||||||
--host=${ARCH}-apple-darwin \
|
--host=${ARCH}-apple-darwin \
|
||||||
@@ -111,10 +123,14 @@ do
|
|||||||
${EXTRA_FLAGS}
|
${EXTRA_FLAGS}
|
||||||
|
|
||||||
echo "Installing opus for $ARCH..."
|
echo "Installing opus for $ARCH..."
|
||||||
|
echo "make clean"
|
||||||
make clean
|
make clean
|
||||||
|
echo "make -j$NJOB V=1"
|
||||||
make -j$NJOB V=1
|
make -j$NJOB V=1
|
||||||
|
echo "make install"
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
echo "cd $SCRIPT_DIR"
|
||||||
cd $SCRIPT_DIR
|
cd $SCRIPT_DIR
|
||||||
|
|
||||||
if [ -d $DIST_DIR/bin ]
|
if [ -d $DIST_DIR/bin ]
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ source config.sh
|
|||||||
SCRIPT_DIR=$( (cd -P $(dirname $0) && pwd) )
|
SCRIPT_DIR=$( (cd -P $(dirname $0) && pwd) )
|
||||||
DIST_DIR_BASE=${DIST_DIR_BASE:="$SCRIPT_DIR/dist"}
|
DIST_DIR_BASE=${DIST_DIR_BASE:="$SCRIPT_DIR/dist"}
|
||||||
|
|
||||||
git submodule update --init opus
|
|
||||||
cd opus
|
cd opus
|
||||||
git checkout master
|
git checkout master
|
||||||
git pull origin master
|
git pull origin master
|
||||||
|
|||||||
@@ -1,33 +1,51 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="7706" systemVersion="14D136" 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>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<objects>
|
<objects>
|
||||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
|
||||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
|
||||||
<view contentMode="scaleToFill" id="iN0-l3-epB">
|
<navigationController id="vV9-32-ww6">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="480" height="480"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<navigationBar key="navigationBar" contentMode="scaleToFill" id="y2P-aE-Haa">
|
||||||
<subviews>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||||
<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">
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<rect key="frame" x="19" y="439" width="444" height="21"/>
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<color key="textColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
</navigationBar>
|
||||||
<nil key="highlightedColor"/>
|
<viewControllers>
|
||||||
<variation key="widthClass=compact">
|
<viewController id="l6V-ue-5Om">
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="11"/>
|
<layoutGuides>
|
||||||
</variation>
|
<viewControllerLayoutGuide type="top" id="rEZ-vx-akr"/>
|
||||||
</label>
|
<viewControllerLayoutGuide type="bottom" id="gBD-cy-cth"/>
|
||||||
</subviews>
|
</layoutGuides>
|
||||||
<color key="backgroundColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="calibratedRGB"/>
|
<view key="view" contentMode="scaleToFill" id="6lF-fc-kpK">
|
||||||
<constraints>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<constraint firstAttribute="bottom" secondItem="8ie-xW-0ye" secondAttribute="bottom" constant="20" id="Gnz-uJ-CDw"/>
|
<animations/>
|
||||||
<constraint firstAttribute="centerX" secondItem="8ie-xW-0ye" secondAttribute="centerX" id="ZEH-qu-HZ9"/>
|
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</constraints>
|
</view>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<navigationItem key="navigationItem" id="rW0-BH-s7l">
|
||||||
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
|
<barButtonItem key="leftBarButtonItem" enabled="NO" id="d9R-Zo-Uml">
|
||||||
<point key="canvasLocation" x="404" y="445"/>
|
<button key="customView" opaque="NO" contentMode="center" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="9JC-B5-BAE">
|
||||||
</view>
|
<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>
|
</objects>
|
||||||
|
<resources>
|
||||||
|
<image name="Logo" width="32" height="32"/>
|
||||||
|
</resources>
|
||||||
</document>
|
</document>
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
//
|
|
||||||
// App.h
|
|
||||||
// Moonlight
|
|
||||||
//
|
|
||||||
// Created by Diego Waxemberg on 10/22/14.
|
|
||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
|
||||||
|
|
||||||
@interface App : NSObject
|
|
||||||
|
|
||||||
@property NSString* appId;
|
|
||||||
@property NSString* appName;
|
|
||||||
@property UIImage* appImage;
|
|
||||||
@property BOOL isRunning;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
//
|
|
||||||
// App.m
|
|
||||||
// Moonlight
|
|
||||||
//
|
|
||||||
// Created by Diego Waxemberg on 10/22/14.
|
|
||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import "App.h"
|
|
||||||
#import "HttpManager.h"
|
|
||||||
|
|
||||||
@implementation App
|
|
||||||
@synthesize appId, appName, appImage, isRunning;
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -83,10 +83,7 @@ static NSOperationQueue* mainQueue;
|
|||||||
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
|
NSManagedObjectContext *managedObjectContext = self.managedObjectContext;
|
||||||
if (managedObjectContext != nil) {
|
if (managedObjectContext != nil) {
|
||||||
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
if ([managedObjectContext hasChanges] && ![managedObjectContext save:&error]) {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
|
||||||
// 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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -103,7 +100,7 @@ static NSOperationQueue* mainQueue;
|
|||||||
|
|
||||||
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
|
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
|
||||||
if (coordinator != nil) {
|
if (coordinator != nil) {
|
||||||
_managedObjectContext = [[NSManagedObjectContext alloc] init];
|
_managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
|
||||||
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
|
[_managedObjectContext setPersistentStoreCoordinator:coordinator];
|
||||||
}
|
}
|
||||||
return _managedObjectContext;
|
return _managedObjectContext;
|
||||||
@@ -136,32 +133,15 @@ static NSOperationQueue* mainQueue;
|
|||||||
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
|
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
|
||||||
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
|
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil];
|
||||||
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
|
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error]) {
|
||||||
/*
|
// Log the error
|
||||||
Replace this implementation with code to handle the error appropriately.
|
Log(LOG_E, @"Critical database error: %@, %@", error, [error userInfo]);
|
||||||
|
|
||||||
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.
|
// Drop the database
|
||||||
|
[[NSFileManager defaultManager] removeItemAtURL:storeURL error:nil];
|
||||||
Typical reasons for an error here include:
|
|
||||||
* The persistent store is not accessible;
|
// Try again
|
||||||
* The schema for the persistent store is incompatible with current managed object model.
|
return [self persistentStoreCoordinator];
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return _persistentStoreCoordinator;
|
return _persistentStoreCoordinator;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -11,11 +11,11 @@
|
|||||||
@interface CryptoManager : NSObject
|
@interface CryptoManager : NSObject
|
||||||
|
|
||||||
+ (void) generateKeyPairUsingSSl;
|
+ (void) generateKeyPairUsingSSl;
|
||||||
+ (NSString*) getUniqueID;
|
|
||||||
+ (NSData*) readCertFromFile;
|
+ (NSData*) readCertFromFile;
|
||||||
+ (NSData*) readKeyFromFile;
|
+ (NSData*) readKeyFromFile;
|
||||||
+ (NSData*) readP12FromFile;
|
+ (NSData*) readP12FromFile;
|
||||||
+ (NSData*) getSignatureFromCert:(NSData*)cert;
|
+ (NSData*) getSignatureFromCert:(NSData*)cert;
|
||||||
|
+ (NSData*) nullTerminateString:(NSData*)data;
|
||||||
|
|
||||||
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN;
|
- (NSData*) createAESKeyFromSalt:(NSData*)saltedPIN;
|
||||||
- (NSData*) SHA1HashData:(NSData*)data;
|
- (NSData*) SHA1HashData:(NSData*)data;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "mkcert.h"
|
#import "mkcert.h"
|
||||||
#import <AdSupport/ASIdentifierManager.h>
|
|
||||||
|
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
#include <openssl/sha.h>
|
#include <openssl/sha.h>
|
||||||
@@ -76,8 +75,14 @@ static NSData* p12 = nil;
|
|||||||
return (((int)[data length] + 15) / 16) * 16;
|
return (((int)[data length] + 15) / 16) * 16;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (NSData*) nullTerminateString:(NSData*)data {
|
||||||
|
NSMutableData* mutData = [NSMutableData dataWithData:data];
|
||||||
|
[mutData appendBytes:"" length:1];
|
||||||
|
return mutData;
|
||||||
|
}
|
||||||
|
|
||||||
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert {
|
- (bool) verifySignature:(NSData *)data withSignature:(NSData*)signature andCert:(NSData*)cert {
|
||||||
const char* buffer = [cert bytes];
|
const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
|
||||||
X509* x509;
|
X509* x509;
|
||||||
BIO* bio = BIO_new(BIO_s_mem());
|
BIO* bio = BIO_new(BIO_s_mem());
|
||||||
BIO_puts(bio, buffer);
|
BIO_puts(bio, buffer);
|
||||||
@@ -105,7 +110,7 @@ static NSData* p12 = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSData *)signData:(NSData *)data withKey:(NSData *)key {
|
- (NSData *)signData:(NSData *)data withKey:(NSData *)key {
|
||||||
const char* buffer = [key bytes];
|
const char* buffer = [[CryptoManager nullTerminateString:key] bytes];
|
||||||
BIO* bio = BIO_new(BIO_s_mem());
|
BIO* bio = BIO_new(BIO_s_mem());
|
||||||
BIO_puts(bio, buffer);
|
BIO_puts(bio, buffer);
|
||||||
|
|
||||||
@@ -188,7 +193,7 @@ static NSData* p12 = nil;
|
|||||||
}
|
}
|
||||||
|
|
||||||
+ (NSData *)getSignatureFromCert:(NSData *)cert {
|
+ (NSData *)getSignatureFromCert:(NSData *)cert {
|
||||||
const char* buffer = [cert bytes];
|
const char* buffer = [[CryptoManager nullTerminateString:cert] bytes];
|
||||||
X509* x509;
|
X509* x509;
|
||||||
BIO* bio = BIO_new(BIO_s_mem());
|
BIO* bio = BIO_new(BIO_s_mem());
|
||||||
BIO_puts(bio, buffer);
|
BIO_puts(bio, buffer);
|
||||||
@@ -223,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
|
@end
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -85,7 +85,6 @@ int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int years) {
|
|||||||
|
|
||||||
if (*pkeyp == NULL) {
|
if (*pkeyp == NULL) {
|
||||||
if ((pk=EVP_PKEY_new()) == NULL) {
|
if ((pk=EVP_PKEY_new()) == NULL) {
|
||||||
abort();
|
|
||||||
return(0);
|
return(0);
|
||||||
}
|
}
|
||||||
} else {
|
} 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);
|
rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL);
|
||||||
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
if (!EVP_PKEY_assign_RSA(pk, rsa)) {
|
||||||
abort();
|
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// App+CoreDataProperties.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 7/10/15.
|
||||||
|
// Copyright © 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
// Delete this file and regenerate it using "Create NSManagedObject Subclass…"
|
||||||
|
// to keep your implementation up to date with your model.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "App.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface App (CoreDataProperties)
|
||||||
|
|
||||||
|
@property (nullable, nonatomic, retain) NSString *id;
|
||||||
|
@property (nullable, nonatomic, retain) NSData *image;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *name;
|
||||||
|
@property (nullable, nonatomic, retain) Host *host;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
//
|
||||||
|
// App.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 7/10/15.
|
||||||
|
// Copyright © 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <CoreData/CoreData.h>
|
||||||
|
|
||||||
|
@class Host;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface App : NSManagedObject
|
||||||
|
|
||||||
|
@property BOOL isRunning;
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(App *)other;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
#import "App+CoreDataProperties.h"
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
//
|
||||||
|
// App.m
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 7/10/15.
|
||||||
|
// Copyright © 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "App.h"
|
||||||
|
#import "Host.h"
|
||||||
|
|
||||||
|
@implementation App
|
||||||
|
|
||||||
|
@synthesize isRunning;
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(App *)other {
|
||||||
|
return [self.name caseInsensitiveCompare:other.name];
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
@@ -10,6 +10,8 @@
|
|||||||
#import "Settings.h"
|
#import "Settings.h"
|
||||||
#import "AppDelegate.h"
|
#import "AppDelegate.h"
|
||||||
#import "Host.h"
|
#import "Host.h"
|
||||||
|
#import "App.h"
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
|
||||||
@interface DataManager : NSObject
|
@interface DataManager : NSObject
|
||||||
|
|
||||||
@@ -18,8 +20,10 @@
|
|||||||
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
|
- (void) saveSettingsWithBitrate:(NSInteger)bitrate framerate:(NSInteger)framerate height:(NSInteger)height width:(NSInteger)width onscreenControls:(NSInteger)onscreenControls;
|
||||||
- (Settings*) retrieveSettings;
|
- (Settings*) retrieveSettings;
|
||||||
- (NSArray*) retrieveHosts;
|
- (NSArray*) retrieveHosts;
|
||||||
- (void) saveHosts;
|
- (void) saveData;
|
||||||
- (Host*) createHost;
|
- (Host*) createHost;
|
||||||
- (void) removeHost:(Host*)host;
|
- (void) removeHost:(Host*)host;
|
||||||
|
- (App*) addAppFromTemporaryApp:(TemporaryApp*)tempApp;
|
||||||
|
- (void) removeAppFromHost:(App*)app;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -7,9 +7,18 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
|
||||||
@implementation DataManager
|
@implementation DataManager
|
||||||
|
|
||||||
|
+ (NSObject *)databaseLock {
|
||||||
|
static NSObject *lock = nil;
|
||||||
|
if (lock == nil) {
|
||||||
|
lock = [[NSObject alloc] init];
|
||||||
|
}
|
||||||
|
return lock;
|
||||||
|
}
|
||||||
|
|
||||||
- (id) init {
|
- (id) init {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
self.appDelegate = [[UIApplication sharedApplication] delegate];
|
self.appDelegate = [[UIApplication sharedApplication] delegate];
|
||||||
@@ -48,38 +57,74 @@
|
|||||||
|
|
||||||
- (Host*) createHost {
|
- (Host*) createHost {
|
||||||
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
NSEntityDescription* entity = [NSEntityDescription entityForName:@"Host" inManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||||
Host* host = [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
return [[Host alloc] initWithEntity:entity insertIntoManagedObjectContext:[self.appDelegate managedObjectContext]];
|
||||||
return host;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) removeHost:(Host*)host {
|
- (void) removeHost:(Host*)host {
|
||||||
[[self.appDelegate managedObjectContext] deleteObject:host];
|
[[self.appDelegate managedObjectContext] deleteObject:host];
|
||||||
|
[self saveData];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) saveHosts {
|
- (void) saveData {
|
||||||
NSError* error;
|
@synchronized([DataManager databaseLock]) {
|
||||||
if (![[self.appDelegate managedObjectContext] save:&error]) {
|
NSError* error;
|
||||||
Log(LOG_E, @"Unable to save hosts to database: %@", 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 {
|
- (NSArray*) retrieveHosts {
|
||||||
return [self fetchRecords:@"Host"];
|
return [self fetchRecords:@"Host"];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSArray*) fetchRecords:(NSString*)entityName {
|
- (App*) addAppFromTemporaryApp:(TemporaryApp*)tempApp {
|
||||||
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;
|
App* managedApp;
|
||||||
NSArray* fetchedRecords = [[self.appDelegate managedObjectContext] executeFetchRequest:fetchRequest error:&error];
|
|
||||||
//TODO: handle errors
|
@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) removeAppFromHost:(App*)app {
|
||||||
|
@synchronized([DataManager databaseLock]) {
|
||||||
|
assert(app.host != nil);
|
||||||
|
|
||||||
|
[app.host removeAppListObject:app];
|
||||||
|
[[self.appDelegate managedObjectContext] deleteObject:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSArray*) fetchRecords:(NSString*)entityName {
|
||||||
|
NSArray* fetchedRecords;
|
||||||
|
|
||||||
|
@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;
|
return fetchedRecords;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
//
|
||||||
|
// Host+CoreDataProperties.h
|
||||||
|
// Moonlight
|
||||||
|
//
|
||||||
|
// Created by Diego Waxemberg on 7/10/15.
|
||||||
|
// Copyright © 2015 Limelight Stream. All rights reserved.
|
||||||
|
//
|
||||||
|
// Delete this file and regenerate it using "Create NSManagedObject Subclass…"
|
||||||
|
// to keep your implementation up to date with your model.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "Host.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface Host (CoreDataProperties)
|
||||||
|
|
||||||
|
@property (nullable, nonatomic, retain) NSString *address;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *externalAddress;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *localAddress;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *mac;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *name;
|
||||||
|
@property (nullable, nonatomic, retain) NSNumber *pairState;
|
||||||
|
@property (nullable, nonatomic, retain) NSString *uuid;
|
||||||
|
@property (nullable, nonatomic, retain) NSSet *appList;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@interface Host (CoreDataGeneratedAccessors)
|
||||||
|
|
||||||
|
- (void)addAppListObject:(NSManagedObject *)value;
|
||||||
|
- (void)removeAppListObject:(NSManagedObject *)value;
|
||||||
|
- (void)addAppList:(NSSet *)values;
|
||||||
|
- (void)removeAppList:(NSSet *)values;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
@@ -2,23 +2,26 @@
|
|||||||
// Host.h
|
// Host.h
|
||||||
// Moonlight
|
// Moonlight
|
||||||
//
|
//
|
||||||
// Created by Diego Waxemberg on 10/28/14.
|
// Created by Diego Waxemberg on 7/10/15.
|
||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
// Copyright © 2015 Limelight Stream. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import <Foundation/Foundation.h>
|
#import <Foundation/Foundation.h>
|
||||||
#import <CoreData/CoreData.h>
|
#import <CoreData/CoreData.h>
|
||||||
#import "Utils.h"
|
#import "Utils.h"
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
@interface Host : NSManagedObject
|
@interface Host : NSManagedObject
|
||||||
|
|
||||||
@property (nonatomic, retain) NSString * name;
|
|
||||||
@property (nonatomic, retain) NSString * address;
|
|
||||||
@property (nonatomic, retain) NSString * localAddress;
|
|
||||||
@property (nonatomic, retain) NSString * externalAddress;
|
|
||||||
@property (nonatomic, retain) NSString * uuid;
|
|
||||||
@property (nonatomic, retain) NSString * mac;
|
|
||||||
@property (nonatomic) BOOL online;
|
@property (nonatomic) BOOL online;
|
||||||
@property (nonatomic) PairState pairState;
|
@property (nonatomic) PairState pairState;
|
||||||
|
@property (nonatomic) NSString * activeAddress;
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(Host *)other;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
||||||
|
|
||||||
|
#import "Host+CoreDataProperties.h"
|
||||||
@@ -2,22 +2,20 @@
|
|||||||
// Host.m
|
// Host.m
|
||||||
// Moonlight
|
// Moonlight
|
||||||
//
|
//
|
||||||
// Created by Diego Waxemberg on 10/28/14.
|
// Created by Diego Waxemberg on 7/10/15.
|
||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
// Copyright © 2015 Limelight Stream. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#import "Host.h"
|
#import "Host.h"
|
||||||
|
|
||||||
|
|
||||||
@implementation Host
|
@implementation Host
|
||||||
|
|
||||||
@dynamic name;
|
|
||||||
@dynamic address;
|
|
||||||
@dynamic localAddress;
|
|
||||||
@dynamic externalAddress;
|
|
||||||
@dynamic uuid;
|
|
||||||
@dynamic mac;
|
|
||||||
@dynamic pairState;
|
@dynamic pairState;
|
||||||
@synthesize online;
|
@synthesize online;
|
||||||
|
@synthesize activeAddress;
|
||||||
|
|
||||||
|
- (NSComparisonResult)compareName:(Host *)other {
|
||||||
|
return [self.name caseInsensitiveCompare:other.name];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -17,5 +17,6 @@
|
|||||||
@property (nonatomic, retain) NSNumber * height;
|
@property (nonatomic, retain) NSNumber * height;
|
||||||
@property (nonatomic, retain) NSNumber * width;
|
@property (nonatomic, retain) NSNumber * width;
|
||||||
@property (nonatomic, retain) NSNumber * onscreenControls;
|
@property (nonatomic, retain) NSNumber * onscreenControls;
|
||||||
|
@property (nonatomic, retain) NSString * uniqueId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -16,5 +16,6 @@
|
|||||||
@dynamic height;
|
@dynamic height;
|
||||||
@dynamic width;
|
@dynamic width;
|
||||||
@dynamic onscreenControls;
|
@dynamic onscreenControls;
|
||||||
|
@dynamic uniqueId;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -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
|
||||||
@@ -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
|
||||||
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "a_button_80x80@2x.png",
|
||||||
"filename" : "a_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "a_button_120x120@3x.png",
|
||||||
"filename" : "a_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "a_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.2 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "b_button_80x80@2x.png",
|
||||||
"filename" : "b_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "b_button_120x120@3x.png",
|
||||||
"filename" : "b_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "b_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "down_61x75@2x.png",
|
||||||
"filename" : "down_31x38@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "down_93x114@3x.png",
|
||||||
"filename" : "down_61x75@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "down_93x114@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "left_76x61@2x.png",
|
||||||
"filename" : "left_38x31@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "left_114x92@3x.png",
|
||||||
"filename" : "left_76x61@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "left_114x92@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,21 @@
|
|||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x",
|
||||||
|
"filename" : "play.png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"version" : 1,
|
||||||
|
"author" : "xcode"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 17 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"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 901 B |
|
After Width: | Height: | Size: 812 B |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "right_75x61@2x.png",
|
||||||
"filename" : "right_38x31@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "right_114x93@3x.png",
|
||||||
"filename" : "right_75x61@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "right_114x93@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.2 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "up_61x76@2x.png",
|
||||||
"filename" : "up_31x39@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "up_93x116@3x.png",
|
||||||
"filename" : "up_61x76@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "up_93x116@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 1.3 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "x_button_80x80@2x.png",
|
||||||
"filename" : "x_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "x_button_120x120@3x.png",
|
||||||
"filename" : "x_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "x_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.3 KiB |
@@ -2,18 +2,17 @@
|
|||||||
"images" : [
|
"images" : [
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "1x",
|
"filename" : "y_button_80x80@2x.png",
|
||||||
"filename" : "y_button_40x40@1x.png"
|
"scale" : "1x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "2x",
|
"filename" : "y_button_120x120@3x.png",
|
||||||
"filename" : "y_button_80x80@2x.png"
|
"scale" : "2x"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"idiom" : "universal",
|
"idiom" : "universal",
|
||||||
"scale" : "3x",
|
"scale" : "3x"
|
||||||
"filename" : "y_button_120x120@3x.png"
|
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"info" : {
|
"info" : {
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 2.1 KiB |
@@ -63,25 +63,30 @@
|
|||||||
BOOL l3Set;
|
BOOL l3Set;
|
||||||
BOOL r3Set;
|
BOOL r3Set;
|
||||||
|
|
||||||
|
BOOL _iPad;
|
||||||
|
CGRect _controlArea;
|
||||||
UIView* _view;
|
UIView* _view;
|
||||||
OnScreenControlsLevel _level;
|
OnScreenControlsLevel _level;
|
||||||
|
|
||||||
ControllerSupport *_controllerSupport;
|
ControllerSupport *_controllerSupport;
|
||||||
Controller *_controller;
|
Controller *_controller;
|
||||||
id<EdgeDetectionDelegate> _edgeDelegate;
|
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_SIZE = 50;
|
||||||
static const float BUTTON_DIST = 20;
|
static const float BUTTON_DIST = 20;
|
||||||
static float BUTTON_CENTER_X;
|
static float BUTTON_CENTER_X;
|
||||||
static float BUTTON_CENTER_Y;
|
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_X;
|
||||||
static float D_PAD_CENTER_Y;
|
static float D_PAD_CENTER_Y;
|
||||||
|
|
||||||
|
static const float DEAD_ZONE_PADDING = 15;
|
||||||
|
|
||||||
static const double STICK_CLICK_RATE = 100;
|
static const double STICK_CLICK_RATE = 100;
|
||||||
static const float STICK_DEAD_ZONE = .1;
|
static const float STICK_DEAD_ZONE = .1;
|
||||||
static float STICK_INNER_SIZE;
|
static float STICK_INNER_SIZE;
|
||||||
@@ -117,6 +122,21 @@ static float L3_Y;
|
|||||||
_controller = [[Controller alloc] init];
|
_controller = [[Controller alloc] init];
|
||||||
_controller.playerIndex = 0;
|
_controller.playerIndex = 0;
|
||||||
_edgeDelegate = swipeDelegate;
|
_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];
|
_aButton = [CALayer layer];
|
||||||
_bButton = [CALayer layer];
|
_bButton = [CALayer layer];
|
||||||
@@ -139,7 +159,7 @@ static float L3_Y;
|
|||||||
_leftStick = [CALayer layer];
|
_leftStick = [CALayer layer];
|
||||||
_rightStick = [CALayer layer];
|
_rightStick = [CALayer layer];
|
||||||
_edge = [CALayer layer];
|
_edge = [CALayer layer];
|
||||||
|
|
||||||
[self setupEdgeDetection];
|
[self setupEdgeDetection];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@@ -167,10 +187,10 @@ static float L3_Y;
|
|||||||
|
|
||||||
[self hideButtons];
|
[self hideButtons];
|
||||||
[self hideBumpers];
|
[self hideBumpers];
|
||||||
|
[self hideL3R3];
|
||||||
[self drawTriggers];
|
[self drawTriggers];
|
||||||
[self drawStartSelect];
|
[self drawStartSelect];
|
||||||
[self drawSticks];
|
[self drawSticks];
|
||||||
[self drawL3R3];
|
|
||||||
break;
|
break;
|
||||||
case OnScreenControlsLevelAutoGCExtendedGamepad:
|
case OnScreenControlsLevelAutoGCExtendedGamepad:
|
||||||
// GCExtendedGamepad is missing R3, L3, and select
|
// GCExtendedGamepad is missing R3, L3, and select
|
||||||
@@ -219,8 +239,8 @@ static float L3_Y;
|
|||||||
// Start with the default complex layout
|
// Start with the default complex layout
|
||||||
[self setupComplexControls];
|
[self setupComplexControls];
|
||||||
|
|
||||||
START_Y = _view.frame.size.height * .9;
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
SELECT_Y = _view.frame.size.height * .9;
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For GCGamepad controls we move triggers, start, and select
|
// For GCGamepad controls we move triggers, start, and select
|
||||||
@@ -229,7 +249,42 @@ static float L3_Y;
|
|||||||
// Start with the default complex layout
|
// Start with the default complex layout
|
||||||
[self setupComplexControls];
|
[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
|
// 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
|
// Start with the default complex layout
|
||||||
[self setupComplexControls];
|
[self setupComplexControls];
|
||||||
|
|
||||||
START_Y = _view.frame.size.height * .9;
|
START_X = _controlArea.size.width * .6 + _controlArea.origin.x;
|
||||||
SELECT_Y = _view.frame.size.height * .9;
|
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;
|
R2_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
L2_Y = _view.frame.size.height * .9;
|
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) setupComplexControls
|
- (void) setupComplexControls
|
||||||
{
|
{
|
||||||
D_PAD_CENTER_X = _view.frame.size.width * .15;
|
D_PAD_CENTER_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
D_PAD_CENTER_Y = _view.frame.size.height * .55;
|
D_PAD_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
|
||||||
BUTTON_CENTER_X = _view.frame.size.width * .85;
|
BUTTON_CENTER_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
BUTTON_CENTER_Y = _view.frame.size.height * .55;
|
BUTTON_CENTER_Y = _controlArea.size.height * .60 + _controlArea.origin.y;
|
||||||
|
|
||||||
LS_CENTER_X = _view.frame.size.width * .35;
|
if (_iPad)
|
||||||
LS_CENTER_Y = _view.frame.size.height * .75;
|
{
|
||||||
RS_CENTER_X = _view.frame.size.width * .65;
|
// The analog sticks are kept closer to the sides on iPad
|
||||||
RS_CENTER_Y = _view.frame.size.height * .75;
|
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_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
START_Y = _view.frame.size.height * .1;
|
START_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
SELECT_X = _view.frame.size.width * .4;
|
SELECT_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
SELECT_Y = _view.frame.size.height * .1;
|
SELECT_Y = _controlArea.size.height * .9 + _controlArea.origin.y;
|
||||||
|
|
||||||
L1_X = _view.frame.size.width * .15;
|
L1_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
L1_Y = _view.frame.size.height * .27;
|
L1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
|
||||||
L2_X = _view.frame.size.width * .15;
|
L2_X = _controlArea.size.width * .1 + _controlArea.origin.x;
|
||||||
L2_Y = _view.frame.size.height * .1;
|
L2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
|
||||||
R1_X = _view.frame.size.width * .85;
|
R1_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
R1_Y = _view.frame.size.height * .27;
|
R1_Y = _controlArea.size.height * .27 + _controlArea.origin.y;
|
||||||
R2_X = _view.frame.size.width * .85;
|
R2_X = _controlArea.size.width * .9 + _controlArea.origin.x;
|
||||||
R2_Y = _view.frame.size.height * .1;
|
R2_Y = _controlArea.size.height * .1 + _controlArea.origin.y;
|
||||||
L3_X = _view.frame.size.width * .25;
|
L3_X = _controlArea.size.width * .25 + _controlArea.origin.x;
|
||||||
L3_Y = _view.frame.size.height * .75;
|
L3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
R3_X = _view.frame.size.width * .75;
|
R3_X = _controlArea.size.width * .75 + _controlArea.origin.x;
|
||||||
R3_Y = _view.frame.size.height * .75;
|
R3_Y = _controlArea.size.height * .75 + _controlArea.origin.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) drawButtons {
|
- (void) drawButtons {
|
||||||
@@ -285,43 +353,43 @@ static float L3_Y;
|
|||||||
_aButton.contents = (id) aButtonImage.CGImage;
|
_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);
|
_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];
|
[_view.layer addSublayer:_aButton];
|
||||||
|
|
||||||
// create B button
|
// create B button
|
||||||
UIImage* bButtonImage = [UIImage imageNamed:@"BButton"];
|
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.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;
|
_bButton.contents = (id) bButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_bButton];
|
[_view.layer addSublayer:_bButton];
|
||||||
|
|
||||||
// create X Button
|
// create X Button
|
||||||
UIImage* xButtonImage = [UIImage imageNamed:@"XButton"];
|
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.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;
|
_xButton.contents = (id) xButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_xButton];
|
[_view.layer addSublayer:_xButton];
|
||||||
|
|
||||||
// create Y Button
|
// create Y Button
|
||||||
UIImage* yButtonImage = [UIImage imageNamed:@"YButton"];
|
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.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;
|
_yButton.contents = (id) yButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_yButton];
|
[_view.layer addSublayer:_yButton];
|
||||||
|
|
||||||
// create Down button
|
// create Down button
|
||||||
UIImage* downButtonImage = [UIImage imageNamed:@"DownButton"];
|
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.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;
|
_downButton.contents = (id) downButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_downButton];
|
[_view.layer addSublayer:_downButton];
|
||||||
|
|
||||||
// create Right button
|
// create Right button
|
||||||
UIImage* rightButtonImage = [UIImage imageNamed:@"RightButton"];
|
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.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;
|
_rightButton.contents = (id) rightButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_rightButton];
|
[_view.layer addSublayer:_rightButton];
|
||||||
|
|
||||||
// create Up button
|
// create Up button
|
||||||
UIImage* upButtonImage = [UIImage imageNamed:@"UpButton"];
|
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.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;
|
_upButton.contents = (id) upButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_upButton];
|
[_view.layer addSublayer:_upButton];
|
||||||
|
|
||||||
// create Left button
|
// create Left button
|
||||||
UIImage* leftButtonImage = [UIImage imageNamed:@"LeftButton"];
|
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);
|
_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.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;
|
_startButton.contents = (id) startButtonImage.CGImage;
|
||||||
[_view.layer addSublayer:_startButton];
|
[_view.layer addSublayer:_startButton];
|
||||||
|
|
||||||
// create Select button
|
// create Select button
|
||||||
UIImage* selectButtonImage = [UIImage imageNamed:@"SelectButton"];
|
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);
|
_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.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;
|
_leftStick.contents = (id) leftStickImage.CGImage;
|
||||||
[_view.layer addSublayer:_leftStick];
|
[_view.layer addSublayer:_leftStick];
|
||||||
|
|
||||||
// create right analog stick
|
// create right analog stick
|
||||||
UIImage* rightStickBgImage = [UIImage imageNamed:@"StickOuter"];
|
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);
|
_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 lsMaxY = LS_CENTER_Y + STICK_OUTER_SIZE / 2;
|
||||||
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
|
float lsMinX = LS_CENTER_X - STICK_OUTER_SIZE / 2;
|
||||||
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
|
float lsMinY = LS_CENTER_Y - STICK_OUTER_SIZE / 2;
|
||||||
|
|
||||||
for (UITouch* touch in touches) {
|
for (UITouch* touch in touches) {
|
||||||
CGPoint touchLocation = [touch locationInView:_view];
|
CGPoint touchLocation = [touch locationInView:_view];
|
||||||
float xLoc = touchLocation.x;
|
float xLoc = touchLocation.x;
|
||||||
@@ -473,34 +541,34 @@ static float L3_Y;
|
|||||||
if (xLoc < lsMinX) xLoc = lsMinX;
|
if (xLoc < lsMinX) xLoc = lsMinX;
|
||||||
if (yLoc > lsMaxY) yLoc = lsMaxY;
|
if (yLoc > lsMaxY) yLoc = lsMaxY;
|
||||||
if (yLoc < lsMinY) yLoc = lsMinY;
|
if (yLoc < lsMinY) yLoc = lsMinY;
|
||||||
|
|
||||||
_leftStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
_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 xStickVal = (xLoc - LS_CENTER_X) / (lsMaxX - LS_CENTER_X);
|
||||||
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
|
float yStickVal = (yLoc - LS_CENTER_Y) / (lsMaxY - LS_CENTER_Y);
|
||||||
|
|
||||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||||
|
|
||||||
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
[_controllerSupport updateLeftStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _rsTouch) {
|
} else if (touch == _rsTouch) {
|
||||||
if (xLoc > rsMaxX) xLoc = rsMaxX;
|
if (xLoc > rsMaxX) xLoc = rsMaxX;
|
||||||
if (xLoc < rsMinX) xLoc = rsMinX;
|
if (xLoc < rsMinX) xLoc = rsMinX;
|
||||||
if (yLoc > rsMaxY) yLoc = rsMaxY;
|
if (yLoc > rsMaxY) yLoc = rsMaxY;
|
||||||
if (yLoc < rsMinY) yLoc = rsMinY;
|
if (yLoc < rsMinY) yLoc = rsMinY;
|
||||||
|
|
||||||
_rightStick.frame = CGRectMake(xLoc - STICK_INNER_SIZE / 2, yLoc - STICK_INNER_SIZE / 2, STICK_INNER_SIZE, STICK_INNER_SIZE);
|
_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 xStickVal = (xLoc - RS_CENTER_X) / (rsMaxX - RS_CENTER_X);
|
||||||
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
|
float yStickVal = (yLoc - RS_CENTER_Y) / (rsMaxY - RS_CENTER_Y);
|
||||||
|
|
||||||
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
if (fabsf(xStickVal) < STICK_DEAD_ZONE) xStickVal = 0;
|
||||||
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
if (fabsf(yStickVal) < STICK_DEAD_ZONE) yStickVal = 0;
|
||||||
|
|
||||||
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
[_controllerSupport updateRightStick:_controller x:0x7FFE * xStickVal y:0x7FFE * -yStickVal];
|
||||||
|
|
||||||
updated = true;
|
updated = true;
|
||||||
} else if (touch == _aTouch) {
|
} else if (touch == _aTouch) {
|
||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
@@ -535,11 +603,14 @@ static float L3_Y;
|
|||||||
} else if (touch == _r3Touch) {
|
} else if (touch == _r3Touch) {
|
||||||
buttonTouch = true;
|
buttonTouch = true;
|
||||||
}
|
}
|
||||||
|
if ([_deadTouches containsObject:touch]) {
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished:_controller];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
return updated || buttonTouch;
|
return updated || buttonTouch;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)handleTouchDownEvent:touches {
|
- (BOOL)handleTouchDownEvent:touches {
|
||||||
@@ -653,6 +724,10 @@ static float L3_Y;
|
|||||||
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
|
} else if ([_edge.presentationLayer hitTest:touchLocation]) {
|
||||||
_edgeTouch = touch;
|
_edgeTouch = touch;
|
||||||
}
|
}
|
||||||
|
if (!updated && !stickTouch && [self isInDeadZone:touch]) {
|
||||||
|
[_deadTouches addObject:touch];
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished:_controller];
|
[_controllerSupport updateFinished:_controller];
|
||||||
@@ -744,15 +819,123 @@ static float L3_Y;
|
|||||||
touched = true;
|
touched = true;
|
||||||
} else if (touch == _edgeTouch) {
|
} else if (touch == _edgeTouch) {
|
||||||
_edgeTouch = nil;
|
_edgeTouch = nil;
|
||||||
if (![_edge.presentationLayer hitTest:[touch locationInView:_view]]) {
|
if ([touch locationInView:_view].x >= _view.frame.size.width / 4) {
|
||||||
[_edgeDelegate edgeSwiped];
|
[_edgeDelegate edgeSwiped];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if ([_deadTouches containsObject:touch]) {
|
||||||
|
[_deadTouches removeObject:touch];
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (updated) {
|
if (updated) {
|
||||||
[_controllerSupport updateFinished:_controller];
|
[_controllerSupport updateFinished:_controller];
|
||||||
}
|
}
|
||||||
|
|
||||||
return updated || touched;
|
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
|
@end
|
||||||
@@ -67,15 +67,16 @@
|
|||||||
deltaX *= xDeltaFactor * screenFactor;
|
deltaX *= xDeltaFactor * screenFactor;
|
||||||
deltaY *= yDeltaFactor * screenFactor;
|
deltaY *= yDeltaFactor * screenFactor;
|
||||||
|
|
||||||
LiSendMouseMoveEvent(deltaX, deltaY);
|
if (deltaX != 0 || deltaY != 0) {
|
||||||
|
LiSendMouseMoveEvent(deltaX, deltaY);
|
||||||
touchMoved = true;
|
touchMoved = true;
|
||||||
touchLocation = currentLocation;
|
touchLocation = currentLocation;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if ([[event allTouches] count] == 2) {
|
} else if ([[event allTouches] count] == 2) {
|
||||||
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
|
CGPoint firstLocation = [[[[event allTouches] allObjects] objectAtIndex:0] locationInView:self];
|
||||||
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
|
CGPoint secondLocation = [[[[event allTouches] allObjects] objectAtIndex:1] locationInView:self];
|
||||||
|
|
||||||
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
|
CGPoint avgLocation = CGPointMake((firstLocation.x + secondLocation.x) / 2, (firstLocation.y + secondLocation.y) / 2);
|
||||||
if (touchLocation.y != avgLocation.y) {
|
if (touchLocation.y != avgLocation.y) {
|
||||||
LiSendScrollEvent(avgLocation.y - touchLocation.y);
|
LiSendScrollEvent(avgLocation.y - touchLocation.y);
|
||||||
@@ -93,23 +94,23 @@
|
|||||||
if (!touchMoved) {
|
if (!touchMoved) {
|
||||||
if ([[event allTouches] count] == 2) {
|
if ([[event allTouches] count] == 2) {
|
||||||
Log(LOG_D, @"Sending right mouse button press");
|
Log(LOG_D, @"Sending right mouse button press");
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_RIGHT);
|
||||||
|
|
||||||
// Wait 100 ms to simulate a real button press
|
// Wait 100 ms to simulate a real button press
|
||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_RIGHT);
|
||||||
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Log(LOG_D, @"Sending left mouse button press");
|
Log(LOG_D, @"Sending left mouse button press");
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_PRESS, BUTTON_LEFT);
|
||||||
|
|
||||||
// Wait 100 ms to simulate a real button press
|
// Wait 100 ms to simulate a real button press
|
||||||
usleep(100 * 1000);
|
usleep(100 * 1000);
|
||||||
|
|
||||||
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
LiSendMouseButtonEvent(BUTTON_ACTION_RELEASE, BUTTON_LEFT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
<key>CFBundleExecutable</key>
|
<key>CFBundleExecutable</key>
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
<string>${EXECUTABLE_NAME}</string>
|
||||||
<key>CFBundleIdentifier</key>
|
<key>CFBundleIdentifier</key>
|
||||||
<string>com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)</string>
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
<string>6.0</string>
|
<string>6.0</string>
|
||||||
<key>CFBundleName</key>
|
<key>CFBundleName</key>
|
||||||
@@ -17,15 +17,20 @@
|
|||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
<key>CFBundleShortVersionString</key>
|
||||||
<string>0.9.1</string>
|
<string>1.0.1</string>
|
||||||
<key>CFBundleSignature</key>
|
<key>CFBundleSignature</key>
|
||||||
<string>????</string>
|
<string>????</string>
|
||||||
<key>CFBundleVersion</key>
|
<key>CFBundleVersion</key>
|
||||||
<string>1</string>
|
<string>4</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
<string>public.app-category.games</string>
|
<string>public.app-category.games</string>
|
||||||
<key>LSRequiresIPhoneOS</key>
|
<key>LSRequiresIPhoneOS</key>
|
||||||
<true/>
|
<true/>
|
||||||
|
<key>NSAppTransportSecurity</key>
|
||||||
|
<dict>
|
||||||
|
<key>NSAllowsArbitraryLoads</key>
|
||||||
|
<true/>
|
||||||
|
</dict>
|
||||||
<key>UIAppFonts</key>
|
<key>UIAppFonts</key>
|
||||||
<array>
|
<array>
|
||||||
<string>Roboto-Black.ttf</string>
|
<string>Roboto-Black.ttf</string>
|
||||||
@@ -45,9 +50,9 @@
|
|||||||
<array>
|
<array>
|
||||||
<string>armv7</string>
|
<string>armv7</string>
|
||||||
</array>
|
</array>
|
||||||
<key>UIStatusBarHidden</key>
|
<key>UIRequiresFullScreen</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UIStatusBarHidden~ipad</key>
|
<key>UIStatusBarHidden</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>UISupportedInterfaceOrientations</key>
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
<array>
|
<array>
|
||||||
@@ -59,5 +64,7 @@
|
|||||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
</array>
|
</array>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</plist>
|
||||||
@@ -3,6 +3,6 @@
|
|||||||
<plist version="1.0">
|
<plist version="1.0">
|
||||||
<dict>
|
<dict>
|
||||||
<key>_XCCurrentVersionName</key>
|
<key>_XCCurrentVersionName</key>
|
||||||
<string>Limelight 0.3.1.xcdatamodel</string>
|
<string>Moonlight v1.0-2.xcdatamodel</string>
|
||||||
</dict>
|
</dict>
|
||||||
</plist>
|
</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>
|
||||||
@@ -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" 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="135"/>
|
||||||
|
</elements>
|
||||||
|
</model>
|
||||||
@@ -20,7 +20,7 @@
|
|||||||
@interface AppAssetManager : NSObject
|
@interface AppAssetManager : NSObject
|
||||||
|
|
||||||
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
- (id) initWithCallback:(id<AppAssetCallback>)callback;
|
||||||
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host;
|
- (void) retrieveAssetsFromHost:(Host*)host;
|
||||||
- (void) stopRetrieving;
|
- (void) stopRetrieving;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -15,8 +15,6 @@
|
|||||||
@implementation AppAssetManager {
|
@implementation AppAssetManager {
|
||||||
NSOperationQueue* _opQueue;
|
NSOperationQueue* _opQueue;
|
||||||
id<AppAssetCallback> _callback;
|
id<AppAssetCallback> _callback;
|
||||||
Host* _host;
|
|
||||||
NSMutableDictionary* _imageCache;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const int MAX_REQUEST_COUNT = 4;
|
static const int MAX_REQUEST_COUNT = 4;
|
||||||
@@ -24,29 +22,22 @@ static const int MAX_REQUEST_COUNT = 4;
|
|||||||
- (id) initWithCallback:(id<AppAssetCallback>)callback {
|
- (id) initWithCallback:(id<AppAssetCallback>)callback {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
_imageCache = [[NSMutableDictionary alloc] init];
|
|
||||||
_opQueue = [[NSOperationQueue alloc] init];
|
_opQueue = [[NSOperationQueue alloc] init];
|
||||||
[_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT];
|
[_opQueue setMaxConcurrentOperationCount:MAX_REQUEST_COUNT];
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) retrieveAssets:(NSArray*)appList fromHost:(Host*)host {
|
- (void) retrieveAssetsFromHost:(Host*)host {
|
||||||
Host* oldHost = _host;
|
for (App* app in host.appList) {
|
||||||
_host = host;
|
if (app.image == nil) {
|
||||||
BOOL useCache = [oldHost.uuid isEqualToString:_host.uuid];
|
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
|
||||||
Log(LOG_I, @"Using cached app images: %d", useCache);
|
retriever.app = app;
|
||||||
if (!useCache) {
|
retriever.host = host;
|
||||||
[_imageCache removeAllObjects];
|
retriever.callback = _callback;
|
||||||
}
|
|
||||||
for (App* app in appList) {
|
[_opQueue addOperation:retriever];
|
||||||
AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init];
|
}
|
||||||
retriever.app = app;
|
|
||||||
retriever.host = _host;
|
|
||||||
retriever.callback = _callback;
|
|
||||||
retriever.cache = _imageCache;
|
|
||||||
retriever.useCache = useCache;
|
|
||||||
[_opQueue addOperation:retriever];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,8 +15,6 @@
|
|||||||
|
|
||||||
@property (nonatomic) Host* host;
|
@property (nonatomic) Host* host;
|
||||||
@property (nonatomic) App* app;
|
@property (nonatomic) App* app;
|
||||||
@property (nonatomic) NSMutableDictionary* cache;
|
|
||||||
@property (nonatomic) id<AppAssetCallback> callback;
|
@property (nonatomic) id<AppAssetCallback> callback;
|
||||||
@property (nonatomic) BOOL useCache;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -11,40 +11,27 @@
|
|||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "AppAssetResponse.h"
|
#import "AppAssetResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation AppAssetRetriever
|
@implementation AppAssetRetriever
|
||||||
static const double RETRY_DELAY = 2; // seconds
|
static const double RETRY_DELAY = 2; // seconds
|
||||||
static const int MAX_ATTEMPTS = 5;
|
static const int MAX_ATTEMPTS = 5;
|
||||||
|
|
||||||
|
|
||||||
- (void) main {
|
- (void) main {
|
||||||
UIImage* appImage = nil;
|
UIImage* appImage = nil;
|
||||||
int attempts = 0;
|
int attempts = 0;
|
||||||
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
|
while (![self isCancelled] && appImage == nil && attempts++ < MAX_ATTEMPTS) {
|
||||||
if (self.useCache) {
|
|
||||||
@synchronized(self.cache) {
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.activeAddress uniqueId:[IdManager getUniqueId] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
|
||||||
UIImage* cachedImage = [self.cache objectForKey:self.app.appId];
|
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
|
||||||
if (cachedImage != nil) {
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.id]]];
|
||||||
appImage = cachedImage;
|
|
||||||
self.app.appImage = appImage;
|
appImage = [UIImage imageWithData:appAssetResp.data];
|
||||||
}
|
self.app.image = UIImagePNGRepresentation(appImage);
|
||||||
}
|
|
||||||
|
if (![self isCancelled] && appImage == nil) {
|
||||||
|
[NSThread sleepForTimeInterval:RETRY_DELAY];
|
||||||
}
|
}
|
||||||
if (appImage == nil) {
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_host.address uniqueId:[CryptoManager getUniqueID] deviceName:deviceName cert:[CryptoManager readCertFromFile]];
|
|
||||||
AppAssetResponse* appAssetResp = [[AppAssetResponse alloc] init];
|
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appAssetResp withUrlRequest:[hMan newAppAssetRequestWithAppId:self.app.appId]]];
|
|
||||||
|
|
||||||
appImage = [UIImage imageWithData:appAssetResp.data];
|
|
||||||
self.app.appImage = appImage;
|
|
||||||
if (appImage != nil) {
|
|
||||||
@synchronized(self.cache) {
|
|
||||||
[self.cache setObject:appImage forKey:self.app.appId];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[NSThread sleepForTimeInterval:RETRY_DELAY];
|
|
||||||
}
|
}
|
||||||
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
|
[self performSelectorOnMainThread:@selector(sendCallbackForApp:) withObject:self.app waitUntilDone:NO];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
#import "AppListResponse.h"
|
#import "AppListResponse.h"
|
||||||
#import "App.h"
|
#import "TemporaryApp.h"
|
||||||
|
#import "DataManager.h"
|
||||||
#import <libxml2/libxml/xmlreader.h>
|
#import <libxml2/libxml/xmlreader.h>
|
||||||
|
|
||||||
@implementation AppListResponse {
|
@implementation AppListResponse {
|
||||||
@@ -64,8 +65,8 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
|||||||
//Log(LOG_D, @"node: %s", node->name);
|
//Log(LOG_D, @"node: %s", node->name);
|
||||||
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
|
if (!xmlStrcmp(node->name, (xmlChar*)TAG_APP)) {
|
||||||
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
xmlNodePtr appInfoNode = node->xmlChildrenNode;
|
||||||
NSString* appName;
|
NSString* appName = @"";
|
||||||
NSString* appId;
|
NSString* appId = nil;
|
||||||
BOOL appIsRunning = NO;
|
BOOL appIsRunning = NO;
|
||||||
while (appInfoNode != NULL) {
|
while (appInfoNode != NULL) {
|
||||||
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
if (!xmlStrcmp(appInfoNode->name, (xmlChar*)TAG_APP_TITLE)) {
|
||||||
@@ -93,11 +94,11 @@ static const char* TAG_APP_IS_RUNNING = "IsRunning";
|
|||||||
}
|
}
|
||||||
appInfoNode = appInfoNode->next;
|
appInfoNode = appInfoNode->next;
|
||||||
}
|
}
|
||||||
App* app = [[App alloc] init];
|
if (appId != nil) {
|
||||||
app.appName = appName;
|
TemporaryApp* app = [[TemporaryApp alloc] init];
|
||||||
app.appId = appId;
|
app.name = appName;
|
||||||
app.isRunning = appIsRunning;
|
app.id = appId;
|
||||||
if (app.appId != nil) {
|
app.isRunning = appIsRunning;
|
||||||
[_appList addObject:app];
|
[_appList addObject:app];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#import "DataManager.h"
|
#import "DataManager.h"
|
||||||
#import "DiscoveryWorker.h"
|
#import "DiscoveryWorker.h"
|
||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation DiscoveryManager {
|
@implementation DiscoveryManager {
|
||||||
NSMutableArray* _hostQueue;
|
NSMutableArray* _hostQueue;
|
||||||
@@ -27,27 +28,42 @@
|
|||||||
|
|
||||||
- (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback {
|
- (id)initWithHosts:(NSArray *)hosts andCallback:(id<DiscoveryCallback>)callback {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_hostQueue = [NSMutableArray arrayWithArray:hosts];
|
|
||||||
|
// Using addHostToDiscovery ensures no duplicates
|
||||||
|
// will make it into the list from the database
|
||||||
_callback = callback;
|
_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];
|
_opQueue = [[NSOperationQueue alloc] init];
|
||||||
_mdnsMan = [[MDNSManager alloc] initWithCallback:self];
|
_mdnsMan = [[MDNSManager alloc] initWithCallback:self];
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
_uniqueId = [CryptoManager getUniqueID];
|
_uniqueId = [IdManager getUniqueId];
|
||||||
_cert = [CryptoManager readCertFromFile];
|
_cert = [CryptoManager readCertFromFile];
|
||||||
shouldDiscover = NO;
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))callback {
|
- (void) discoverHost:(NSString *)hostAddress withCallback:(void (^)(Host *, NSString*))callback {
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:hostAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
|
ServerInfoResponse* serverInfoResponse = [[ServerInfoResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest]]];
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResponse withUrlRequest:[hMan newServerInfoRequest] fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
|
|
||||||
Host* host = nil;
|
Host* host = nil;
|
||||||
if ([serverInfoResponse isStatusOk]) {
|
if ([serverInfoResponse isStatusOk]) {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
host = [dataMan createHost];
|
host = [dataMan createHost];
|
||||||
host.address = hostAddress;
|
host.activeAddress = host.address = hostAddress;
|
||||||
host.online = YES;
|
host.online = YES;
|
||||||
[serverInfoResponse populateHost:host];
|
[serverInfoResponse populateHost:host];
|
||||||
if (![self addHostToDiscovery:host]) {
|
if (![self addHostToDiscovery:host]) {
|
||||||
@@ -125,7 +141,7 @@
|
|||||||
[dataMan removeHost:host];
|
[dataMan removeHost:host];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[dataMan saveHosts];
|
[dataMan saveData];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,23 +41,83 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSArray*) getHostAddressList {
|
||||||
|
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:3];
|
||||||
|
|
||||||
|
if (_host.localAddress != nil) {
|
||||||
|
[array addObject:_host.localAddress];
|
||||||
|
}
|
||||||
|
if (_host.externalAddress != nil) {
|
||||||
|
[array addObject:_host.externalAddress];
|
||||||
|
}
|
||||||
|
if (_host.address != nil) {
|
||||||
|
[array addObject:_host.address];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove duplicate addresses from the list.
|
||||||
|
// This is done using an array rather than a set
|
||||||
|
// to preserve insertion order of addresses.
|
||||||
|
for (int i = 0; i < [array count]; i++) {
|
||||||
|
NSString *addr1 = [array objectAtIndex:i];
|
||||||
|
|
||||||
|
for (int j = 1; j < [array count]; j++) {
|
||||||
|
if (i == j) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSString *addr2 = [array objectAtIndex:j];
|
||||||
|
|
||||||
|
if ([addr1 isEqualToString:addr2]) {
|
||||||
|
// Remove the last address
|
||||||
|
[array removeObjectAtIndex:j];
|
||||||
|
|
||||||
|
// Begin searching again from the start
|
||||||
|
i = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) discoverHost {
|
- (void) discoverHost {
|
||||||
BOOL receivedResponse = NO;
|
BOOL receivedResponse = NO;
|
||||||
if (!self.cancelled && _host.localAddress != nil) {
|
NSArray *addresses = [self getHostAddressList];
|
||||||
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.localAddress];
|
|
||||||
receivedResponse = [self checkResponse:serverInfoResp];
|
Log(LOG_D, @"%@ has %d unique addresses", _host.name, [addresses count]);
|
||||||
}
|
|
||||||
if (!self.cancelled && !receivedResponse && _host.externalAddress != nil) {
|
// Give the PC 3 tries to respond before declaring it offline
|
||||||
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.externalAddress];
|
for (int i = 0; i < 3; i++) {
|
||||||
receivedResponse = [self checkResponse:serverInfoResp];
|
for (NSString *address in addresses) {
|
||||||
}
|
if (self.cancelled) {
|
||||||
if (!self.cancelled && !receivedResponse && _host.address != nil) {
|
// Get out without updating the status because
|
||||||
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:_host.address];
|
// it might not have finished checking the various
|
||||||
receivedResponse = [self checkResponse:serverInfoResp];
|
// addresses
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ServerInfoResponse* serverInfoResp = [self requestInfoAtAddress:address];
|
||||||
|
receivedResponse = [self checkResponse:serverInfoResp];
|
||||||
|
if (receivedResponse) {
|
||||||
|
_host.activeAddress = address;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (receivedResponse) {
|
||||||
|
Log(LOG_I, @"Received serverinfo response on try %d", i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Wait for one second then retry
|
||||||
|
[NSThread sleepForTimeInterval:1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_host.online = receivedResponse;
|
_host.online = receivedResponse;
|
||||||
if (receivedResponse) {
|
if (receivedResponse) {
|
||||||
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online);
|
Log(LOG_D, @"Received response from: %@\n{\n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", _host.name, _host.address, _host.localAddress, _host.externalAddress, _host.uuid, _host.mac, _host.pairState, _host.online, _host.activeAddress);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +128,8 @@ static const float POLL_RATE = 2.0f; // Poll every 2 seconds
|
|||||||
cert:_cert];
|
cert:_cert];
|
||||||
ServerInfoResponse* response = [[ServerInfoResponse alloc] init];
|
ServerInfoResponse* response = [[ServerInfoResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:response
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:response
|
||||||
withUrlRequest:[hMan newServerInfoRequest]]];
|
withUrlRequest:[hMan newServerInfoRequest]
|
||||||
|
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
#import "HttpResponse.h"
|
#import "HttpResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
|
||||||
@interface HttpManager : NSObject <NSURLConnectionDelegate, NSURLConnectionDataDelegate>
|
@interface HttpManager : NSObject <NSURLSessionDelegate>
|
||||||
|
|
||||||
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
- (id) initWithHost:(NSString*) host uniqueId:(NSString*) uniqueId deviceName:(NSString*) deviceName cert:(NSData*) cert;
|
||||||
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
- (NSURLRequest*) newPairRequest:(NSData*)salt;
|
||||||
@@ -22,12 +22,12 @@
|
|||||||
- (NSURLRequest*) newPairChallenge;
|
- (NSURLRequest*) newPairChallenge;
|
||||||
- (NSURLRequest*) newAppListRequest;
|
- (NSURLRequest*) newAppListRequest;
|
||||||
- (NSURLRequest*) newServerInfoRequest;
|
- (NSURLRequest*) newServerInfoRequest;
|
||||||
|
- (NSURLRequest*) newHttpServerInfoRequest;
|
||||||
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid;
|
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid;
|
||||||
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
|
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId;
|
||||||
- (NSURLRequest*) newQuitAppRequest;
|
- (NSURLRequest*) newQuitAppRequest;
|
||||||
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
|
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString*)appId;
|
||||||
- (void) executeRequestSynchronously:(HttpRequest*)request;
|
- (void) executeRequestSynchronously:(HttpRequest*)request;
|
||||||
- (void) executeRequest:(HttpRequest*)request;
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
@implementation HttpManager {
|
@implementation HttpManager {
|
||||||
NSString* _baseURL;
|
NSURLSession* _urlSession;
|
||||||
|
NSString* _baseHTTPURL;
|
||||||
|
NSString* _baseHTTPSURL;
|
||||||
NSString* _host;
|
NSString* _host;
|
||||||
NSString* _uniqueId;
|
NSString* _uniqueId;
|
||||||
NSString* _deviceName;
|
NSString* _deviceName;
|
||||||
@@ -27,7 +29,8 @@
|
|||||||
BOOL _errorOccurred;
|
BOOL _errorOccurred;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const NSString* PORT = @"47984";
|
static const NSString* HTTP_PORT = @"47989";
|
||||||
|
static const NSString* HTTPS_PORT = @"47984";
|
||||||
|
|
||||||
+ (NSData*) fixXmlVersion:(NSData*) xmlData {
|
+ (NSData*) fixXmlVersion:(NSData*) xmlData {
|
||||||
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
|
NSString* dataString = [[NSString alloc] initWithData:xmlData encoding:NSUTF8StringEncoding];
|
||||||
@@ -42,38 +45,63 @@ static const NSString* PORT = @"47984";
|
|||||||
_uniqueId = uniqueId;
|
_uniqueId = uniqueId;
|
||||||
_deviceName = deviceName;
|
_deviceName = deviceName;
|
||||||
_cert = cert;
|
_cert = cert;
|
||||||
_baseURL = [[NSString stringWithFormat:@"https://%@:%@", host, PORT]
|
_baseHTTPURL = [NSString stringWithFormat:@"http://%@:%@", host, HTTP_PORT];
|
||||||
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
_baseHTTPSURL = [NSString stringWithFormat:@"https://%@:%@", host, HTTPS_PORT];
|
||||||
_requestLock = dispatch_semaphore_create(0);
|
_requestLock = dispatch_semaphore_create(0);
|
||||||
_respData = [[NSMutableData alloc] init];
|
_respData = [[NSMutableData alloc] init];
|
||||||
|
NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
||||||
|
_urlSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) executeRequestSynchronously:(HttpRequest*)request {
|
- (void) executeRequestSynchronously:(HttpRequest*)request {
|
||||||
Log(LOG_D, @"Making Request: %@", request);
|
Log(LOG_D, @"Making Request: %@", request);
|
||||||
[_respData setLength:0];
|
[_respData setLength:0];
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
[[_urlSession dataTaskWithRequest:request.request completionHandler:^(NSData * __nullable data, NSURLResponse * __nullable response, NSError * __nullable error) {
|
||||||
[NSURLConnection connectionWithRequest:request.request delegate:self];
|
|
||||||
});
|
if (error != NULL) {
|
||||||
|
Log(LOG_D, @"Connection error: %@", error);
|
||||||
|
_errorOccurred = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log(LOG_D, @"Received response: %@", response);
|
||||||
|
|
||||||
|
if (data != NULL) {
|
||||||
|
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
||||||
|
[_respData appendData:data];
|
||||||
|
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
|
||||||
|
_requestResp = [HttpManager fixXmlVersion:_respData];
|
||||||
|
} else {
|
||||||
|
_requestResp = _respData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch_semaphore_signal(_requestLock);
|
||||||
|
}] resume];
|
||||||
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
|
dispatch_semaphore_wait(_requestLock, DISPATCH_TIME_FOREVER);
|
||||||
|
|
||||||
if (!_errorOccurred && request.response) {
|
if (!_errorOccurred && request.response) {
|
||||||
[request.response populateWithData:_requestResp];
|
[request.response populateWithData:_requestResp];
|
||||||
|
|
||||||
|
// If the fallback error code was detected, issue the fallback request
|
||||||
|
if (request.response.statusCode == request.fallbackError && request.fallbackRequest != NULL) {
|
||||||
|
Log(LOG_D, @"Request failed with fallback error code: %d", request.fallbackError);
|
||||||
|
request.request = request.fallbackRequest;
|
||||||
|
request.fallbackError = 0;
|
||||||
|
request.fallbackRequest = NULL;
|
||||||
|
[self executeRequestSynchronously:request];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_errorOccurred = false;
|
_errorOccurred = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) executeRequest:(HttpRequest*)request {
|
|
||||||
[NSURLConnection connectionWithRequest:request.request delegate:self];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
|
- (NSURLRequest*) createRequestFromString:(NSString*) urlString enableTimeout:(BOOL)normalTimeout {
|
||||||
NSString* escapedUrl = [urlString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
|
NSURL* url = [[NSURL alloc] initWithString:urlString];
|
||||||
NSURL* url = [[NSURL alloc] initWithString:escapedUrl];
|
|
||||||
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
|
NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url];
|
||||||
if (normalTimeout) {
|
if (normalTimeout) {
|
||||||
// Timeout the request after 5 seconds
|
// Timeout the request after 7 seconds
|
||||||
[request setTimeoutInterval:5];
|
[request setTimeoutInterval:7];
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Timeout the request after 60 seconds
|
// Timeout the request after 60 seconds
|
||||||
@@ -84,67 +112,72 @@ static const NSString* PORT = @"47984";
|
|||||||
|
|
||||||
- (NSURLRequest*) newPairRequest:(NSData*)salt {
|
- (NSURLRequest*) newPairRequest:(NSData*)salt {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=getservercert&salt=%@&clientcert=%@",
|
||||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
|
_baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:salt], [self bytesToHex:_cert]];
|
||||||
// This call blocks while waiting for the user to input the PIN on the PC
|
// This call blocks while waiting for the user to input the PIN on the PC
|
||||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newUnpairRequest {
|
- (NSURLRequest*) newUnpairRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/unpair?uniqueid=%@", _baseHTTPSURL, _uniqueId];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
|
- (NSURLRequest*) newChallengeRequest:(NSData*)challenge {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientchallenge=%@",
|
||||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
|
_baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challenge]];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
|
- (NSURLRequest*) newChallengeRespRequest:(NSData*)challengeResp {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&serverchallengeresp=%@",
|
||||||
_baseURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
|
_baseHTTPSURL, _uniqueId, _deviceName, [self bytesToHex:challengeResp]];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
|
- (NSURLRequest*) newClientSecretRespRequest:(NSString*)clientPairSecret {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseURL, _uniqueId, _deviceName, clientPairSecret];
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&clientpairingsecret=%@", _baseHTTPSURL, _uniqueId, _deviceName, clientPairSecret];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newPairChallenge {
|
- (NSURLRequest*) newPairChallenge {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseURL, _uniqueId, _deviceName];
|
NSString* urlString = [NSString stringWithFormat:@"%@/pair?uniqueid=%@&devicename=%@&updateState=1&phrase=pairchallenge", _baseHTTPSURL, _uniqueId, _deviceName];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest *)newAppListRequest {
|
- (NSURLRequest *)newAppListRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/applist?uniqueid=%@", _baseHTTPSURL, _uniqueId];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest *)newServerInfoRequest {
|
- (NSURLRequest *)newServerInfoRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo?uniqueid=%@", _baseHTTPSURL, _uniqueId];
|
||||||
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSURLRequest *)newHttpServerInfoRequest {
|
||||||
|
NSString* urlString = [NSString stringWithFormat:@"%@/serverinfo", _baseHTTPURL];
|
||||||
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
return [self createRequestFromString:urlString enableTimeout:TRUE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid {
|
- (NSURLRequest*) newLaunchRequest:(NSString*)appId width:(int)width height:(int)height refreshRate:(int)refreshRate rikey:(NSString*)rikey rikeyid:(int)rikeyid {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid];
|
NSString* urlString = [NSString stringWithFormat:@"%@/launch?uniqueid=%@&appid=%@&mode=%dx%dx%d&additionalStates=1&sops=1&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, appId, width, height, refreshRate, rikey, rikeyid];
|
||||||
// This blocks while the app is launching
|
// This blocks while the app is launching
|
||||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId {
|
- (NSURLRequest*) newResumeRequestWithRiKey:(NSString*)riKey riKeyId:(int)riKeyId {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseURL, _uniqueId, riKey, riKeyId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/resume?uniqueid=%@&rikey=%@&rikeyid=%d", _baseHTTPSURL, _uniqueId, riKey, riKeyId];
|
||||||
// This blocks while the app is resuming
|
// This blocks while the app is resuming
|
||||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newQuitAppRequest {
|
- (NSURLRequest*) newQuitAppRequest {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseURL, _uniqueId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/cancel?uniqueid=%@", _baseHTTPSURL, _uniqueId];
|
||||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId {
|
- (NSURLRequest*) newAppAssetRequestWithAppId:(NSString *)appId {
|
||||||
NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseURL, _uniqueId, appId];
|
NSString* urlString = [NSString stringWithFormat:@"%@/appasset?uniqueid=%@&appid=%@&AssetType=2&AssetIdx=0", _baseHTTPSURL, _uniqueId, appId];
|
||||||
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
return [self createRequestFromString:urlString enableTimeout:FALSE];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,33 +190,6 @@ static const NSString* PORT = @"47984";
|
|||||||
return hex;
|
return hex;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
|
|
||||||
Log(LOG_D, @"Received response: %@", response);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
|
|
||||||
Log(LOG_D, @"\n\nReceived data: %@\n\n", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]);
|
|
||||||
[_respData appendData:data];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
|
|
||||||
if ([[NSString alloc] initWithData:_respData encoding:NSUTF8StringEncoding] != nil) {
|
|
||||||
_requestResp = [HttpManager fixXmlVersion:_respData];
|
|
||||||
} else {
|
|
||||||
_requestResp = _respData;
|
|
||||||
}
|
|
||||||
dispatch_semaphore_signal(_requestLock);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
|
|
||||||
SecIdentityRef identity = [self getClientCertificate];
|
|
||||||
NSArray *certArray = [self getCertificate:identity];
|
|
||||||
|
|
||||||
NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
|
|
||||||
|
|
||||||
[challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns an array containing the certificate
|
// Returns an array containing the certificate
|
||||||
- (NSArray*)getCertificate:(SecIdentityRef) identity {
|
- (NSArray*)getCertificate:(SecIdentityRef) identity {
|
||||||
SecCertificateRef certificate = nil;
|
SecCertificateRef certificate = nil;
|
||||||
@@ -219,10 +225,25 @@ static const NSString* PORT = @"47984";
|
|||||||
return identityApp;
|
return identityApp;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
|
- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * __nullable))completionHandler {
|
||||||
Log(LOG_D, @"connection error: %@", error);
|
// Allow untrusted server certificates
|
||||||
_errorOccurred = true;
|
if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust])
|
||||||
dispatch_semaphore_signal(_requestLock);
|
{
|
||||||
|
completionHandler(NSURLSessionAuthChallengeUseCredential,
|
||||||
|
[NSURLCredential credentialForTrust: challenge.protectionSpace.serverTrust]);
|
||||||
|
}
|
||||||
|
// Respond to client certificate challenge with our certificate
|
||||||
|
else if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate])
|
||||||
|
{
|
||||||
|
SecIdentityRef identity = [self getClientCertificate];
|
||||||
|
NSArray* certArray = [self getCertificate:identity];
|
||||||
|
NSURLCredential* newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certArray persistence:NSURLCredentialPersistencePermanent];
|
||||||
|
completionHandler(NSURLSessionAuthChallengeUseCredential, newCredential);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -13,7 +13,10 @@
|
|||||||
|
|
||||||
@property (nonatomic) id<Response> response;
|
@property (nonatomic) id<Response> response;
|
||||||
@property (nonatomic) NSURLRequest* request;
|
@property (nonatomic) NSURLRequest* request;
|
||||||
|
@property (nonatomic) int fallbackError;
|
||||||
|
@property (nonatomic) NSURLRequest* fallbackRequest;
|
||||||
|
|
||||||
|
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq;
|
||||||
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
|
+ (instancetype) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req;
|
||||||
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
|
+ (instancetype) requestWithUrlRequest:(NSURLRequest*)req;
|
||||||
|
|
||||||
|
|||||||
@@ -25,4 +25,13 @@
|
|||||||
return request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
+ (HttpRequest*) requestForResponse:(id<Response>)response withUrlRequest:(NSURLRequest*)req fallbackError:(int)error fallbackRequest:(NSURLRequest*) fallbackReq {
|
||||||
|
HttpRequest* request = [[HttpRequest alloc] init];
|
||||||
|
request.request = req;
|
||||||
|
request.response = response;
|
||||||
|
request.fallbackError = error;
|
||||||
|
request.fallbackRequest = fallbackReq;
|
||||||
|
return request;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -51,7 +51,7 @@ static NSString* NV_SERVICE_TYPE = @"_nvstream._tcp";
|
|||||||
for (NSNetService* service in services) {
|
for (NSNetService* service in services) {
|
||||||
if (service.hostName != nil) {
|
if (service.hostName != nil) {
|
||||||
Host* host = [dataMan createHost];
|
Host* host = [dataMan createHost];
|
||||||
host.address = service.hostName;
|
host.activeAddress = host.address = service.hostName;
|
||||||
host.name = host.address;
|
host.name = host.address;
|
||||||
[hosts addObject:host];
|
[hosts addObject:host];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,13 +31,14 @@
|
|||||||
|
|
||||||
- (void) main {
|
- (void) main {
|
||||||
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[_httpManager newServerInfoRequest]
|
||||||
|
fallbackError:401 fallbackRequest:[_httpManager newHttpServerInfoRequest]]];
|
||||||
if (serverInfoResp == nil) {
|
if (serverInfoResp == nil) {
|
||||||
[_callback pairFailed:@"Unable to connect to PC"];
|
[_callback pairFailed:@"Unable to connect to PC"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if ([serverInfoResp isStatusOk]) {
|
if ([serverInfoResp isStatusOk]) {
|
||||||
if (![[serverInfoResp getStringTag:@"currentgame"] isEqual:@"0"]) {
|
if (![[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_AVAILABLE"]) {
|
||||||
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
[_callback pairFailed:@"You must stop streaming before attempting to pair."];
|
||||||
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
|
} else if (![[serverInfoResp getStringTag:@"PairStatus"] isEqual:@"1"]) {
|
||||||
[self initiatePair];
|
[self initiatePair];
|
||||||
@@ -60,7 +61,7 @@
|
|||||||
}
|
}
|
||||||
NSInteger pairedStatus;
|
NSInteger pairedStatus;
|
||||||
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
if (![pairResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing was declined by the target."];
|
[_callback pairFailed:@"Pairing was declined by the target."];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -78,8 +79,8 @@
|
|||||||
if (![self verifyResponseStatus:challengeResp]) {
|
if (![self verifyResponseStatus:challengeResp]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
if (![challengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #2 failed"];
|
[_callback pairFailed:@"Pairing stage #2 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -99,8 +100,8 @@
|
|||||||
if (![self verifyResponseStatus:secretResp]) {
|
if (![self verifyResponseStatus:secretResp]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
if (![secretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #3 failed"];
|
[_callback pairFailed:@"Pairing stage #3 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -110,14 +111,14 @@
|
|||||||
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
|
NSData* serverSignature = [serverSecretResp subdataWithRange:NSMakeRange(16, 256)];
|
||||||
|
|
||||||
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
if (![cryptoMan verifySignature:serverSecret withSignature:serverSignature andCert:[Utils hexToBytes:plainCert]]) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Server certificate invalid"];
|
[_callback pairFailed:@"Server certificate invalid"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
NSData* serverChallengeRespHash = [cryptoMan SHA1HashData:[self concatData:[self concatData:randomChallenge with:[CryptoManager getSignatureFromCert:[Utils hexToBytes:plainCert]]] with:serverSecret]];
|
||||||
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
if (![serverChallengeRespHash isEqual:serverResponse]) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Incorrect PIN"];
|
[_callback pairFailed:@"Incorrect PIN"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -128,8 +129,8 @@
|
|||||||
if (![self verifyResponseStatus:clientSecretResp]) {
|
if (![self verifyResponseStatus:clientSecretResp]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
if (![clientSecretResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #4 failed"];
|
[_callback pairFailed:@"Pairing stage #4 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -139,8 +140,8 @@
|
|||||||
if (![self verifyResponseStatus:clientPairChallengeResp]) {
|
if (![self verifyResponseStatus:clientPairChallengeResp]) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || !pairedStatus) {
|
if (![clientPairChallengeResp getIntTag:@"paired" value:&pairedStatus] || pairedStatus != 1) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Pairing stage #5 failed"];
|
[_callback pairFailed:@"Pairing stage #5 failed"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -149,11 +150,11 @@
|
|||||||
|
|
||||||
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
|
- (BOOL) verifyResponseStatus:(HttpResponse*)resp {
|
||||||
if (resp == nil) {
|
if (resp == nil) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:@"Network error occured."];
|
[_callback pairFailed:@"Network error occured."];
|
||||||
return false;
|
return false;
|
||||||
} else if (![resp isStatusOk]) {
|
} else if (![resp isStatusOk]) {
|
||||||
[_httpManager executeRequest:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
[_httpManager executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[_httpManager newUnpairRequest]]];
|
||||||
[_callback pairFailed:resp.statusMessage];
|
[_callback pairFailed:resp.statusMessage];
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
#include "opus.h"
|
#include "opus.h"
|
||||||
|
|
||||||
@implementation Connection {
|
@implementation Connection {
|
||||||
IP_ADDRESS _host;
|
const char* _host;
|
||||||
STREAM_CONFIGURATION _streamConfig;
|
STREAM_CONFIGURATION _streamConfig;
|
||||||
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
CONNECTION_LISTENER_CALLBACKS _clCallbacks;
|
||||||
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
DECODER_RENDERER_CALLBACKS _drCallbacks;
|
||||||
@@ -65,11 +65,16 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit)
|
|||||||
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
|
return [renderer submitDecodeBuffer:data length:decodeUnit->fullLength];
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArInit(void)
|
void ArInit(int audioConfiguration, POPUS_MULTISTREAM_CONFIGURATION opusConfig)
|
||||||
{
|
{
|
||||||
int err;
|
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];
|
audioLock = [[NSLock alloc] init];
|
||||||
|
|
||||||
@@ -77,9 +82,9 @@ void ArInit(void)
|
|||||||
NSError *audioSessionError = nil;
|
NSError *audioSessionError = nil;
|
||||||
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
|
AVAudioSession* audioSession = [AVAudioSession sharedInstance];
|
||||||
|
|
||||||
[audioSession setPreferredSampleRate:48000.0 error:&audioSessionError];
|
[audioSession setPreferredSampleRate:opusConfig->sampleRate error:&audioSessionError];
|
||||||
[audioSession setCategory: AVAudioSessionCategoryPlayback 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 setPreferredIOBufferDuration:0.005 error:&audioSessionError];
|
||||||
[audioSession setActive: YES error: &audioSessionError];
|
[audioSession setActive: YES error: &audioSessionError];
|
||||||
|
|
||||||
@@ -99,11 +104,11 @@ void ArInit(void)
|
|||||||
}
|
}
|
||||||
|
|
||||||
AudioStreamBasicDescription audioFormat = {0};
|
AudioStreamBasicDescription audioFormat = {0};
|
||||||
audioFormat.mSampleRate = 48000;
|
audioFormat.mSampleRate = opusConfig->sampleRate;
|
||||||
audioFormat.mBitsPerChannel = 16;
|
audioFormat.mBitsPerChannel = 16;
|
||||||
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
audioFormat.mFormatID = kAudioFormatLinearPCM;
|
||||||
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
|
audioFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked;
|
||||||
audioFormat.mChannelsPerFrame = 2;
|
audioFormat.mChannelsPerFrame = opusConfig->channelCount;
|
||||||
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
|
audioFormat.mBytesPerFrame = audioFormat.mChannelsPerFrame * (audioFormat.mBitsPerChannel / 8);
|
||||||
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
|
audioFormat.mBytesPerPacket = audioFormat.mBytesPerFrame;
|
||||||
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
|
audioFormat.mFramesPerPacket = audioFormat.mBytesPerPacket / audioFormat.mBytesPerFrame;
|
||||||
@@ -137,16 +142,26 @@ void ArInit(void)
|
|||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to initialize audioUnit: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
status = AudioOutputUnitStart(audioUnit);
|
||||||
|
if (status) {
|
||||||
|
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArRelease(void)
|
void ArCleanup(void)
|
||||||
{
|
{
|
||||||
if (opusDecoder != NULL) {
|
if (opusDecoder != NULL) {
|
||||||
opus_decoder_destroy(opusDecoder);
|
opus_decoder_destroy(opusDecoder);
|
||||||
opusDecoder = NULL;
|
opusDecoder = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
OSStatus status = AudioUnitUninitialize(audioUnit);
|
OSStatus status = AudioOutputUnitStop(audioUnit);
|
||||||
|
if (status) {
|
||||||
|
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = AudioUnitUninitialize(audioUnit);
|
||||||
if (status) {
|
if (status) {
|
||||||
Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status);
|
Log(LOG_E, @"Unable to uninitialize audioUnit: %d", (int32_t)status);
|
||||||
}
|
}
|
||||||
@@ -166,22 +181,6 @@ void ArRelease(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArStart(void)
|
|
||||||
{
|
|
||||||
OSStatus status = AudioOutputUnitStart(audioUnit);
|
|
||||||
if (status) {
|
|
||||||
Log(LOG_E, @"Unable to start audioUnit: %d", (int32_t)status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArStop(void)
|
|
||||||
{
|
|
||||||
OSStatus status = AudioOutputUnitStop(audioUnit);
|
|
||||||
if (status) {
|
|
||||||
Log(LOG_E, @"Unable to stop audioUnit: %d", (int32_t)status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
void ArDecodeAndPlaySample(char* sampleData, int sampleLength)
|
||||||
{
|
{
|
||||||
int decodedLength = opus_decode(opusDecoder, (unsigned char*)sampleData, sampleLength, decodedPcmBuffer, PCM_BUFFER_SIZE / 2, 0);
|
int decodedLength = opus_decode(opusDecoder, (unsigned char*)sampleData, sampleLength, decodedPcmBuffer, PCM_BUFFER_SIZE / 2, 0);
|
||||||
@@ -282,10 +281,12 @@ void ClDisplayTransientMessage(char* message)
|
|||||||
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion
|
-(id) initWithConfig:(StreamConfiguration*)config renderer:(VideoDecoderRenderer*)myRenderer connectionCallbacks:(id<ConnectionCallbacks>)callbacks serverMajorVersion:(int)serverMajorVersion
|
||||||
{
|
{
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_host = config.hostAddr;
|
_host = [config.host cStringUsingEncoding:NSUTF8StringEncoding];
|
||||||
renderer = myRenderer;
|
renderer = myRenderer;
|
||||||
_callbacks = callbacks;
|
_callbacks = callbacks;
|
||||||
_serverMajorVersion = serverMajorVersion;
|
_serverMajorVersion = serverMajorVersion;
|
||||||
|
|
||||||
|
LiInitializeStreamConfiguration(&_streamConfig);
|
||||||
_streamConfig.width = config.width;
|
_streamConfig.width = config.width;
|
||||||
_streamConfig.height = config.height;
|
_streamConfig.height = config.height;
|
||||||
_streamConfig.fps = config.frameRate;
|
_streamConfig.fps = config.frameRate;
|
||||||
@@ -299,18 +300,15 @@ void ClDisplayTransientMessage(char* message)
|
|||||||
int riKeyId = htonl(config.riKeyId);
|
int riKeyId = htonl(config.riKeyId);
|
||||||
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
|
memcpy(_streamConfig.remoteInputAesIv, &riKeyId, sizeof(riKeyId));
|
||||||
|
|
||||||
_drCallbacks.setup = NULL;
|
LiInitializeVideoCallbacks(&_drCallbacks);
|
||||||
_drCallbacks.start = NULL;
|
|
||||||
_drCallbacks.stop = NULL;
|
|
||||||
_drCallbacks.release = NULL;
|
|
||||||
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
_drCallbacks.submitDecodeUnit = DrSubmitDecodeUnit;
|
||||||
|
|
||||||
|
LiInitializeAudioCallbacks(&_arCallbacks);
|
||||||
_arCallbacks.init = ArInit;
|
_arCallbacks.init = ArInit;
|
||||||
_arCallbacks.start = ArStart;
|
_arCallbacks.cleanup = ArCleanup;
|
||||||
_arCallbacks.stop = ArStop;
|
|
||||||
_arCallbacks.release = ArRelease;
|
|
||||||
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
|
_arCallbacks.decodeAndPlaySample = ArDecodeAndPlaySample;
|
||||||
|
|
||||||
|
LiInitializeConnectionCallbacks(&_clCallbacks);
|
||||||
_clCallbacks.stageStarting = ClStageStarting;
|
_clCallbacks.stageStarting = ClStageStarting;
|
||||||
_clCallbacks.stageComplete = ClStageComplete;
|
_clCallbacks.stageComplete = ClStageComplete;
|
||||||
_clCallbacks.stageFailed = ClStageFailed;
|
_clCallbacks.stageFailed = ClStageFailed;
|
||||||
@@ -410,7 +408,6 @@ static OSStatus playbackCallback(void *inRefCon,
|
|||||||
&_clCallbacks,
|
&_clCallbacks,
|
||||||
&_drCallbacks,
|
&_drCallbacks,
|
||||||
&_arCallbacks,
|
&_arCallbacks,
|
||||||
NULL,
|
|
||||||
NULL, 0, _serverMajorVersion);
|
NULL, 0, _serverMajorVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,7 +12,6 @@
|
|||||||
|
|
||||||
@property NSString* host;
|
@property NSString* host;
|
||||||
@property NSString* appID;
|
@property NSString* appID;
|
||||||
@property int hostAddr;
|
|
||||||
@property int width;
|
@property int width;
|
||||||
@property int height;
|
@property int height;
|
||||||
@property int frameRate;
|
@property int frameRate;
|
||||||
|
|||||||
@@ -9,5 +9,5 @@
|
|||||||
#import "StreamConfiguration.h"
|
#import "StreamConfiguration.h"
|
||||||
|
|
||||||
@implementation StreamConfiguration
|
@implementation StreamConfiguration
|
||||||
@synthesize host, appID, hostAddr, width, height, frameRate, bitRate, riKeyId, riKey;
|
@synthesize host, appID, width, height, frameRate, bitRate, riKeyId, riKey;
|
||||||
@end
|
@end
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
#import "HttpResponse.h"
|
#import "HttpResponse.h"
|
||||||
#import "HttpRequest.h"
|
#import "HttpRequest.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation StreamManager {
|
@implementation StreamManager {
|
||||||
StreamConfiguration* _config;
|
StreamConfiguration* _config;
|
||||||
@@ -36,7 +37,7 @@
|
|||||||
|
|
||||||
- (void)main {
|
- (void)main {
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
NSString* uniqueId = [CryptoManager getUniqueID];
|
NSString* uniqueId = [IdManager getUniqueId];
|
||||||
NSData* cert = [CryptoManager readCertFromFile];
|
NSData* cert = [CryptoManager readCertFromFile];
|
||||||
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_config.host
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_config.host
|
||||||
@@ -45,12 +46,13 @@
|
|||||||
cert:cert];
|
cert:cert];
|
||||||
|
|
||||||
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
|
||||||
NSString* currentGame = [serverInfoResp getStringTag:@"currentgame"];
|
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
|
NSString* pairStatus = [serverInfoResp getStringTag:@"PairStatus"];
|
||||||
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
|
NSString* currentClient = [serverInfoResp getStringTag:@"CurrentClient"];
|
||||||
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
NSString* appversion = [serverInfoResp getStringTag:@"appversion"];
|
||||||
if (![serverInfoResp isStatusOk] || currentGame == NULL || pairStatus == NULL || appversion == NULL) {
|
NSString* serverState = [serverInfoResp getStringTag:@"state"];
|
||||||
|
if (![serverInfoResp isStatusOk] || pairStatus == NULL || appversion == NULL || serverState == NULL) {
|
||||||
[_callbacks launchFailed:@"Failed to connect to PC"];
|
[_callbacks launchFailed:@"Failed to connect to PC"];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -62,7 +64,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resumeApp and launchApp handle calling launchFailed
|
// resumeApp and launchApp handle calling launchFailed
|
||||||
if (![currentGame isEqualToString:@"0"]) {
|
if ([serverState hasSuffix:@"_SERVER_BUSY"]) {
|
||||||
if (![currentClient isEqualToString:@"1"]) {
|
if (![currentClient isEqualToString:@"1"]) {
|
||||||
// The server is streaming to someone else
|
// The server is streaming to someone else
|
||||||
[_callbacks launchFailed:@"There is another stream in progress"];
|
[_callbacks launchFailed:@"There is another stream in progress"];
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
@interface UIAppView : UIView
|
@interface UIAppView : UIView
|
||||||
|
|
||||||
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback;
|
- (id) initWithApp:(App*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback;
|
||||||
- (void) updateAppImage;
|
- (void) updateAppImage;
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -12,51 +12,97 @@
|
|||||||
App* _app;
|
App* _app;
|
||||||
UIButton* _appButton;
|
UIButton* _appButton;
|
||||||
UILabel* _appLabel;
|
UILabel* _appLabel;
|
||||||
|
UIImageView* _appOverlay;
|
||||||
|
NSCache* _artCache;
|
||||||
id<AppCallback> _callback;
|
id<AppCallback> _callback;
|
||||||
}
|
}
|
||||||
static int LABEL_DY = 20;
|
|
||||||
|
|
||||||
- (id) initWithApp:(App*)app andCallback:(id<AppCallback>)callback {
|
static UIImage* noImage;
|
||||||
|
|
||||||
|
- (id) initWithApp:(App*)app cache:(NSCache*)cache andCallback:(id<AppCallback>)callback {
|
||||||
self = [super init];
|
self = [super init];
|
||||||
_app = app;
|
_app = app;
|
||||||
_callback = callback;
|
_callback = callback;
|
||||||
|
_artCache = cache;
|
||||||
|
|
||||||
|
// Cache the NoAppImage ourselves to avoid
|
||||||
|
// having to load it each time
|
||||||
|
if (noImage == nil) {
|
||||||
|
noImage = [UIImage imageNamed:@"NoAppImage"];
|
||||||
|
}
|
||||||
|
|
||||||
_appButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
_appButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||||
UIImage* noImage = [UIImage imageNamed:@"NoAppImage"];
|
|
||||||
[_appButton setBackgroundImage:noImage forState:UIControlStateNormal];
|
[_appButton setBackgroundImage:noImage forState:UIControlStateNormal];
|
||||||
[_appButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
|
[_appButton setContentEdgeInsets:UIEdgeInsetsMake(0, 4, 0, 4)];
|
||||||
[_appButton sizeToFit];
|
[_appButton sizeToFit];
|
||||||
[_appButton addTarget:self action:@selector(appClicked) forControlEvents:UIControlEventTouchUpInside];
|
[_appButton addTarget:self action:@selector(appClicked) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|
||||||
[self addSubview:_appButton];
|
[self addSubview:_appButton];
|
||||||
[self sizeToFit];
|
[self sizeToFit];
|
||||||
|
|
||||||
_appButton.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
|
_appButton.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
|
||||||
self.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
|
self.frame = CGRectMake(0, 0, noImage.size.width, noImage.size.height);
|
||||||
|
|
||||||
|
// Rasterizing the cell layer increases rendering performance by quite a bit
|
||||||
|
self.layer.shouldRasterize = YES;
|
||||||
|
self.layer.rasterizationScale = [UIScreen mainScreen].scale;
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateBounds {
|
|
||||||
float x = _appButton.frame.origin.x < _appLabel.frame.origin.x ? _appButton.frame.origin.x : _appLabel.frame.origin.x;
|
|
||||||
float y = _appButton.frame.origin.y < _appLabel.frame.origin.y ? _appButton.frame.origin.y : _appLabel.frame.origin.y;
|
|
||||||
self.bounds = CGRectMake(x , y, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height + LABEL_DY / 2);
|
|
||||||
self.frame = CGRectMake(x , y, _appButton.frame.size.width > _appLabel.frame.size.width ? _appButton.frame.size.width : _appLabel.frame.size.width, _appButton.frame.size.height + _appLabel.frame.size.height + LABEL_DY / 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void) appClicked {
|
- (void) appClicked {
|
||||||
[_callback appClicked:_app];
|
[_callback appClicked:_app];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateAppImage {
|
- (void) updateAppImage {
|
||||||
if (_app.appImage != nil) {
|
if (_appOverlay != nil) {
|
||||||
_appButton.frame = CGRectMake(0, 0, _app.appImage.size.width / 2, _app.appImage.size.height / 2);
|
[_appOverlay removeFromSuperview];
|
||||||
self.frame = CGRectMake(0, 0, _app.appImage.size.width / 2, _app.appImage.size.height / 2);
|
_appOverlay = nil;
|
||||||
[_appButton setBackgroundImage:_app.appImage forState:UIControlStateNormal];
|
|
||||||
[self setNeedsDisplay];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (_app.isRunning) {
|
||||||
|
// Only create the app overlay if needed
|
||||||
|
_appOverlay = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Play"]];
|
||||||
|
_appOverlay.layer.shadowColor = [UIColor blackColor].CGColor;
|
||||||
|
_appOverlay.layer.shadowOffset = CGSizeMake(0, 0);
|
||||||
|
_appOverlay.layer.shadowOpacity = 1;
|
||||||
|
_appOverlay.layer.shadowRadius = 2.0;
|
||||||
|
|
||||||
|
[self addSubview:_appOverlay];
|
||||||
|
|
||||||
|
_appOverlay.frame = CGRectMake(0, 0, noImage.size.width / 2.f, noImage.size.height / 4.f);
|
||||||
|
[_appOverlay setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/6)];
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Improve no-app image detection
|
// TODO: Improve no-app image detection
|
||||||
if (_app.appImage == nil || (_app.appImage.size.width == 130.f && _app.appImage.size.height == 180.f)) { // This size of image might be blank image received from GameStream.
|
BOOL noAppImage = false;
|
||||||
|
|
||||||
|
if (_app.image != nil) {
|
||||||
|
// Load the decoded image from the cache
|
||||||
|
UIImage* appImage = [_artCache objectForKey:_app];
|
||||||
|
if (appImage == nil) {
|
||||||
|
// Not cached; we have to decode this now
|
||||||
|
appImage = [UIImage imageWithData:_app.image];
|
||||||
|
[_artCache setObject:appImage forKey:_app];
|
||||||
|
}
|
||||||
|
|
||||||
|
// This size of image might be blank image received from GameStream.
|
||||||
|
if (!(appImage.size.width == 130.f && appImage.size.height == 180.f)) {
|
||||||
|
_appButton.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
|
||||||
|
self.frame = CGRectMake(0, 0, appImage.size.width / 2, appImage.size.height / 2);
|
||||||
|
_appOverlay.frame = CGRectMake(0, 0, self.frame.size.width / 2.f, self.frame.size.height / 4.f);
|
||||||
|
_appOverlay.layer.shadowRadius = 4.0;
|
||||||
|
[_appOverlay setCenter:CGPointMake(self.frame.size.width/2, self.frame.size.height/6)];
|
||||||
|
[_appButton setBackgroundImage:appImage forState:UIControlStateNormal];
|
||||||
|
[self setNeedsDisplay];
|
||||||
|
} else {
|
||||||
|
noAppImage = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
noAppImage = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (noAppImage) {
|
||||||
_appLabel = [[UILabel alloc] init];
|
_appLabel = [[UILabel alloc] init];
|
||||||
CGFloat padding = 4.f;
|
CGFloat padding = 4.f;
|
||||||
[_appLabel setFrame: CGRectMake(padding, padding, _appButton.frame.size.width - 2 * padding, _appButton.frame.size.height - 2 * padding)];
|
[_appLabel setFrame: CGRectMake(padding, padding, _appButton.frame.size.width - 2 * padding, _appButton.frame.size.height - 2 * padding)];
|
||||||
@@ -66,18 +112,10 @@ static int LABEL_DY = 20;
|
|||||||
[_appLabel setTextAlignment:NSTextAlignmentCenter];
|
[_appLabel setTextAlignment:NSTextAlignmentCenter];
|
||||||
[_appLabel setLineBreakMode:NSLineBreakByWordWrapping];
|
[_appLabel setLineBreakMode:NSLineBreakByWordWrapping];
|
||||||
[_appLabel setNumberOfLines:0];
|
[_appLabel setNumberOfLines:0];
|
||||||
[_appLabel setText:_app.appName];
|
[_appLabel setText:_app.name];
|
||||||
[_appButton addSubview:_appLabel];
|
[_appButton addSubview:_appLabel];
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
// Only override drawRect: if you perform custom drawing.
|
|
||||||
// An empty implementation adversely affects performance during animation.
|
|
||||||
- (void)drawRect:(CGRect)rect {
|
|
||||||
// Drawing code
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
@protocol HostCallback <NSObject>
|
@protocol HostCallback <NSObject>
|
||||||
|
|
||||||
- (void) hostClicked:(Host*)host;
|
- (void) hostClicked:(Host*)host view:(UIView*)view;
|
||||||
- (void) hostLongClicked:(Host*)host view:(UIView*)view;
|
- (void) hostLongClicked:(Host*)host view:(UIView*)view;
|
||||||
- (void) addHostClicked;
|
- (void) addHostClicked;
|
||||||
|
|
||||||
|
|||||||
@@ -171,7 +171,7 @@ static const int LABEL_DY = 20;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) hostClicked {
|
- (void) hostClicked {
|
||||||
[_callback hostClicked:_host];
|
[_callback hostClicked:_host view:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) addClicked {
|
- (void) addClicked {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@import ImageIO;
|
||||||
|
|
||||||
#import "MainFrameViewController.h"
|
#import "MainFrameViewController.h"
|
||||||
#import "CryptoManager.h"
|
#import "CryptoManager.h"
|
||||||
#import "HttpManager.h"
|
#import "HttpManager.h"
|
||||||
@@ -22,89 +24,202 @@
|
|||||||
#import "ServerInfoResponse.h"
|
#import "ServerInfoResponse.h"
|
||||||
#import "StreamFrameViewController.h"
|
#import "StreamFrameViewController.h"
|
||||||
#import "LoadingFrameViewController.h"
|
#import "LoadingFrameViewController.h"
|
||||||
|
#import "ComputerScrollView.h"
|
||||||
|
#import "TemporaryApp.h"
|
||||||
|
#import "IdManager.h"
|
||||||
|
|
||||||
@implementation MainFrameViewController {
|
@implementation MainFrameViewController {
|
||||||
NSOperationQueue* _opQueue;
|
NSOperationQueue* _opQueue;
|
||||||
Host* _selectedHost;
|
Host* _selectedHost;
|
||||||
NSString* _uniqueId;
|
NSString* _uniqueId;
|
||||||
NSData* _cert;
|
NSData* _cert;
|
||||||
NSString* _currentGame;
|
|
||||||
DiscoveryManager* _discMan;
|
DiscoveryManager* _discMan;
|
||||||
AppAssetManager* _appManager;
|
AppAssetManager* _appManager;
|
||||||
StreamConfiguration* _streamConfig;
|
StreamConfiguration* _streamConfig;
|
||||||
UIAlertView* _pairAlert;
|
UIAlertController* _pairAlert;
|
||||||
UIScrollView* hostScrollView;
|
UIScrollView* hostScrollView;
|
||||||
int currentPosition;
|
int currentPosition;
|
||||||
|
NSArray* _sortedAppList;
|
||||||
|
NSCache* _boxArtCache;
|
||||||
}
|
}
|
||||||
static NSMutableSet* hostList;
|
static NSMutableSet* hostList;
|
||||||
static NSArray* appList;
|
|
||||||
|
|
||||||
- (void)showPIN:(NSString *)PIN {
|
- (void)showPIN:(NSString *)PIN {
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing" message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing"
|
||||||
[_pairAlert show];
|
message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[self presentViewController:_pairAlert animated:YES completion:nil];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pairFailed:(NSString *)message {
|
- (void)pairFailed:(NSString *)message {
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[_pairAlert dismissWithClickedButtonIndex:0 animated:NO];
|
[_pairAlert dismissViewControllerAnimated:YES completion:nil];
|
||||||
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Failed" message:message delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
_pairAlert = [UIAlertController alertControllerWithTitle:@"Pairing Failed"
|
||||||
[_pairAlert show];
|
message:message
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[_pairAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
[self presentViewController:_pairAlert animated:YES completion:nil];
|
||||||
|
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
[self hideLoadingFrame];
|
[self hideLoadingFrame];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)pairSuccessful {
|
- (void)pairSuccessful {
|
||||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[_pairAlert dismissWithClickedButtonIndex:0 animated:NO];
|
[_pairAlert dismissViewControllerAnimated:YES completion:nil];
|
||||||
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Succesful" message:@"Successfully paired to host" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
|
||||||
[_pairAlert show];
|
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
[self hideLoadingFrame];
|
[self alreadyPaired];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)alreadyPaired {
|
- (void)alreadyPaired {
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
BOOL usingCachedAppList = false;
|
||||||
|
|
||||||
|
// Capture the host here because it can change once we
|
||||||
|
// leave the main thread
|
||||||
|
Host* host = _selectedHost;
|
||||||
|
|
||||||
|
if ([host.appList count] > 0) {
|
||||||
|
usingCachedAppList = true;
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
_computerNameButton.title = _selectedHost.name;
|
if (host != _selectedHost) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_computerNameButton.title = host.name;
|
||||||
[self.navigationController.navigationBar setNeedsLayout];
|
[self.navigationController.navigationBar setNeedsLayout];
|
||||||
|
|
||||||
|
[self updateAppsForHost:host];
|
||||||
|
[self hideLoadingFrame];
|
||||||
});
|
});
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
}
|
||||||
|
Log(LOG_I, @"Using cached app list: %d", usingCachedAppList);
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
|
|
||||||
AppListResponse* appListResp = [[AppListResponse alloc] init];
|
// Exempt this host from discovery while handling the applist query
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
|
[_discMan removeHostFromDiscovery:host];
|
||||||
if (appListResp == nil || ![appListResp isStatusOk]) {
|
|
||||||
Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage);
|
// Try up to 5 times to get the app list
|
||||||
} else {
|
AppListResponse* appListResp;
|
||||||
appList = [appListResp getAppList];
|
for (int i = 0; i < 5; i++) {
|
||||||
if (appList == nil) {
|
appListResp = [[AppListResponse alloc] init];
|
||||||
Log(LOG_W, @"Failed to parse applist");
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:appListResp withUrlRequest:[hMan newAppListRequest]]];
|
||||||
} else {
|
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
Log(LOG_W, @"Failed to get applist on try %d: %@", i, appListResp.statusMessage);
|
||||||
[self updateApps];
|
|
||||||
});
|
|
||||||
|
|
||||||
[_appManager stopRetrieving];
|
// Wait for one second then retry
|
||||||
[_appManager retrieveAssets:appList fromHost:_selectedHost];
|
[NSThread sleepForTimeInterval:1];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Log(LOG_I, @"App list successfully retreived - took %d tries", i);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
[self hideLoadingFrame];
|
|
||||||
|
[_discMan addHostToDiscovery:host];
|
||||||
|
|
||||||
|
if (appListResp == nil || ![appListResp isStatusOk] || [appListResp getAppList] == nil) {
|
||||||
|
Log(LOG_W, @"Failed to get applist: %@", appListResp.statusMessage);
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self hideLoadingFrame];
|
||||||
|
|
||||||
|
if (host != _selectedHost) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:@"Fetching App List Failed"
|
||||||
|
message:@"The connection to the PC was interrupted."
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[applistAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
[self presentViewController:applistAlert animated:YES completion:nil];
|
||||||
|
host.online = NO;
|
||||||
|
[self showHostSelectionView];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self mergeAppLists:[appListResp getAppList] forHost:host];
|
||||||
|
|
||||||
|
if (host != _selectedHost) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_computerNameButton.title = host.name;
|
||||||
|
[self.navigationController.navigationBar setNeedsLayout];
|
||||||
|
|
||||||
|
[self updateAppsForHost:host];
|
||||||
|
[_appManager stopRetrieving];
|
||||||
|
[_appManager retrieveAssetsFromHost:host];
|
||||||
|
[self hideLoadingFrame];
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) mergeAppLists:(NSArray*) newList forHost:(Host*)host {
|
||||||
|
DataManager* database = [[DataManager alloc] init];
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!appAlreadyInList) {
|
||||||
|
app.host = host;
|
||||||
|
[database addAppFromTemporaryApp:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Keep looping until the list is no longer being mutated
|
||||||
|
} while (appWasRemoved);
|
||||||
|
|
||||||
|
[database saveData];
|
||||||
|
}
|
||||||
|
|
||||||
- (void)showHostSelectionView {
|
- (void)showHostSelectionView {
|
||||||
appList = [[NSArray alloc] init];
|
|
||||||
[_appManager stopRetrieving];
|
[_appManager stopRetrieving];
|
||||||
|
[[[DataManager alloc] init] saveData];
|
||||||
|
_selectedHost = nil;
|
||||||
_computerNameButton.title = @"No Host Selected";
|
_computerNameButton.title = @"No Host Selected";
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
[self.view addSubview:hostScrollView];
|
[self.view addSubview:hostScrollView];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) receivedAssetForApp:(App*)app {
|
- (void) receivedAssetForApp:(App*)app {
|
||||||
[self.collectionView reloadData];
|
// Update the box art cache now so we don't have to do it
|
||||||
|
// on the main thread
|
||||||
|
[self updateBoxArtCacheForApp:app];
|
||||||
|
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self.collectionView reloadData];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)displayDnsFailedDialog {
|
- (void)displayDnsFailedDialog {
|
||||||
@@ -115,17 +230,56 @@ static NSArray* appList;
|
|||||||
[self presentViewController:alert animated:YES completion:nil];
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) hostClicked:(Host *)host {
|
- (void) hostClicked:(Host *)host view:(UIView *)view {
|
||||||
|
// Treat clicks on offline hosts to be long clicks
|
||||||
|
// This shows the context menu with wake, delete, etc. rather
|
||||||
|
// than just hanging for a while and failing as we would in this
|
||||||
|
// code path.
|
||||||
|
if (!host.online && view != nil) {
|
||||||
|
[self hostLongClicked:host view:view];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Log(LOG_D, @"Clicked host: %@", host.name);
|
Log(LOG_D, @"Clicked host: %@", host.name);
|
||||||
[self showLoadingFrame];
|
|
||||||
_selectedHost = host;
|
_selectedHost = host;
|
||||||
|
[self disableNavigation];
|
||||||
|
|
||||||
|
// If we are online, paired, and have a cached app list, skip straight
|
||||||
|
// to the app grid without a loading frame. This is the fast path that users
|
||||||
|
// should hit most.
|
||||||
|
if (host.online && host.pairState == PairStatePaired && host.appList.count > 0) {
|
||||||
|
[self alreadyPaired];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
[self showLoadingFrame];
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]]];
|
|
||||||
|
// Exempt this host from discovery while handling the serverinfo request
|
||||||
|
[_discMan removeHostFromDiscovery:host];
|
||||||
|
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest]
|
||||||
|
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
|
||||||
|
[_discMan addHostToDiscovery:host];
|
||||||
|
|
||||||
if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
|
if (serverInfoResp == nil || ![serverInfoResp isStatusOk]) {
|
||||||
Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage);
|
Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage);
|
||||||
[self hideLoadingFrame];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self hideLoadingFrame];
|
||||||
|
|
||||||
|
if (host != _selectedHost) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:@"Fetching Server Info Failed"
|
||||||
|
message:@"The connection to the PC was interrupted."
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
[applistAlert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
[self presentViewController:applistAlert animated:YES completion:nil];
|
||||||
|
host.online = NO;
|
||||||
|
[self showHostSelectionView];
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
Log(LOG_D, @"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]);
|
Log(LOG_D, @"server info pair status: %@", [serverInfoResp getStringTag:@"PairStatus"]);
|
||||||
if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
|
if ([[serverInfoResp getStringTag:@"PairStatus"] isEqualToString:@"1"]) {
|
||||||
@@ -145,14 +299,7 @@ static NSArray* appList;
|
|||||||
- (void)hostLongClicked:(Host *)host view:(UIView *)view {
|
- (void)hostLongClicked:(Host *)host view:(UIView *)view {
|
||||||
Log(LOG_D, @"Long clicked host: %@", host.name);
|
Log(LOG_D, @"Long clicked host: %@", host.name);
|
||||||
UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
|
UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:@"" preferredStyle:UIAlertControllerStyleActionSheet];
|
||||||
if (host.online) {
|
if (!host.online) {
|
||||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Unpair" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:host.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
|
||||||
[hMan executeRequest:[HttpRequest requestWithUrlRequest:[hMan newUnpairRequest]]];
|
|
||||||
});
|
|
||||||
}]];
|
|
||||||
} else {
|
|
||||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Wake" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Wake" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||||
UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:@"Wake On Lan" message:@"" preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:@"Wake On Lan" message:@"" preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[wolAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
[wolAlert addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
||||||
@@ -201,7 +348,7 @@ static NSArray* appList;
|
|||||||
[_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){
|
[_discMan discoverHost:hostAddress withCallback:^(Host* host, NSString* error){
|
||||||
if (host != nil) {
|
if (host != nil) {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
[dataMan saveHosts];
|
[dataMan saveData];
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList addObject:host];
|
[hostList addObject:host];
|
||||||
@@ -223,15 +370,10 @@ static NSArray* appList;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) appClicked:(App *)app {
|
- (void) appClicked:(App *)app {
|
||||||
Log(LOG_D, @"Clicked app: %@", app.appName);
|
Log(LOG_D, @"Clicked app: %@", app.name);
|
||||||
_streamConfig = [[StreamConfiguration alloc] init];
|
_streamConfig = [[StreamConfiguration alloc] init];
|
||||||
_streamConfig.host = _selectedHost.address;
|
_streamConfig.host = app.host.activeAddress;
|
||||||
_streamConfig.hostAddr = [Utils resolveHost:_selectedHost.address];
|
_streamConfig.appID = app.id;
|
||||||
_streamConfig.appID = app.appId;
|
|
||||||
if (_streamConfig.hostAddr == 0) {
|
|
||||||
[self displayDnsFailedDialog];
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
Settings* streamSettings = [dataMan retrieveSettings];
|
Settings* streamSettings = [dataMan retrieveSettings];
|
||||||
@@ -247,30 +389,63 @@ static NSArray* appList;
|
|||||||
[[self revealViewController] revealToggle:self];
|
[[self revealViewController] revealToggle:self];
|
||||||
}
|
}
|
||||||
|
|
||||||
App* currentApp = [self findRunningApp];
|
App* currentApp = [self findRunningApp:app.host];
|
||||||
if (currentApp != nil) {
|
if (currentApp != nil) {
|
||||||
UIAlertController* alertController = [UIAlertController
|
UIAlertController* alertController = [UIAlertController
|
||||||
alertControllerWithTitle: app.appName
|
alertControllerWithTitle: app.name
|
||||||
message: [app.appId isEqualToString:currentApp.appId] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.appName]preferredStyle:UIAlertControllerStyleAlert];
|
message: [app.id isEqualToString:currentApp.id] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.name]preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[alertController addAction:[UIAlertAction
|
[alertController addAction:[UIAlertAction
|
||||||
actionWithTitle:[app.appId isEqualToString:currentApp.appId] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
actionWithTitle:[app.id isEqualToString:currentApp.id] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||||
Log(LOG_I, @"Resuming application: %@", currentApp.appName);
|
Log(LOG_I, @"Resuming application: %@", currentApp.name);
|
||||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||||
}]];
|
}]];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:
|
[alertController addAction:[UIAlertAction actionWithTitle:
|
||||||
[app.appId isEqualToString:currentApp.appId] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
[app.id isEqualToString:currentApp.id] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
Log(LOG_I, @"Quitting application: %@", currentApp.appName);
|
Log(LOG_I, @"Quitting application: %@", currentApp.name);
|
||||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.address uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:app.host.activeAddress uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
||||||
[hMan executeRequestSynchronously:[HttpRequest requestWithUrlRequest:[hMan newQuitAppRequest]]];
|
HttpResponse* quitResponse = [[HttpResponse alloc] init];
|
||||||
// TODO: handle failure to quit app
|
HttpRequest* quitRequest = [HttpRequest requestForResponse: quitResponse withUrlRequest:[hMan newQuitAppRequest]];
|
||||||
currentApp.isRunning = NO;
|
|
||||||
|
|
||||||
if (![app.appId isEqualToString:currentApp.appId]) {
|
// Exempt this host from discovery while handling the quit operation
|
||||||
|
[_discMan removeHostFromDiscovery:app.host];
|
||||||
|
[hMan executeRequestSynchronously:quitRequest];
|
||||||
|
[_discMan addHostToDiscovery:app.host];
|
||||||
|
|
||||||
|
UIAlertController* alert;
|
||||||
|
|
||||||
|
// If it fails, display an error and stop the current operation
|
||||||
|
if (quitResponse.statusCode != 200) {
|
||||||
|
alert = [UIAlertController alertControllerWithTitle:@"Quitting App Failed"
|
||||||
|
message:@"Failed to quit app. If this app was started by "
|
||||||
|
"another device, you'll need to quit from that device."
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
}
|
||||||
|
// If it succeeds and we're to start streaming, segue to the stream and return
|
||||||
|
else if (![app.id isEqualToString:currentApp.id]) {
|
||||||
|
currentApp.isRunning = NO;
|
||||||
|
|
||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self updateAppsForHost:app.host];
|
||||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
// Otherwise, display a dialog to notify the user that the app was quit
|
||||||
|
else {
|
||||||
|
currentApp.isRunning = NO;
|
||||||
|
|
||||||
|
alert = [UIAlertController alertControllerWithTitle:@"Quitting App"
|
||||||
|
message:@"The app was quit successfully."
|
||||||
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
|
}
|
||||||
|
|
||||||
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
||||||
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
|
[self updateAppsForHost:app.host];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}]];
|
}]];
|
||||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||||
@@ -280,8 +455,8 @@ static NSArray* appList;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (App*) findRunningApp {
|
- (App*) findRunningApp:(Host*)host {
|
||||||
for (App* app in appList) {
|
for (App* app in host.appList) {
|
||||||
if (app.isRunning) {
|
if (app.isRunning) {
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
@@ -311,6 +486,7 @@ static NSArray* appList;
|
|||||||
|
|
||||||
- (void) hideLoadingFrame {
|
- (void) hideLoadingFrame {
|
||||||
[self dismissViewControllerAnimated:YES completion:nil];
|
[self dismissViewControllerAnimated:YES completion:nil];
|
||||||
|
[self enableNavigation];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidLoad
|
- (void)viewDidLoad
|
||||||
@@ -335,7 +511,7 @@ static NSArray* appList;
|
|||||||
|
|
||||||
// Set up crypto
|
// Set up crypto
|
||||||
[CryptoManager generateKeyPairUsingSSl];
|
[CryptoManager generateKeyPairUsingSSl];
|
||||||
_uniqueId = [CryptoManager getUniqueID];
|
_uniqueId = [IdManager getUniqueId];
|
||||||
_cert = [CryptoManager readCertFromFile];
|
_cert = [CryptoManager readCertFromFile];
|
||||||
|
|
||||||
_appManager = [[AppAssetManager alloc] initWithCallback:self];
|
_appManager = [[AppAssetManager alloc] initWithCallback:self];
|
||||||
@@ -346,19 +522,54 @@ static NSArray* appList;
|
|||||||
hostList = [[NSMutableSet alloc] init];
|
hostList = [[NSMutableSet alloc] init];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_boxArtCache = [[NSCache alloc] init];
|
||||||
|
|
||||||
[self setAutomaticallyAdjustsScrollViewInsets:NO];
|
[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.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 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];
|
[self retrieveSavedHosts];
|
||||||
_discMan = [[DiscoveryManager alloc] initWithHosts:[hostList allObjects] andCallback:self];
|
_discMan = [[DiscoveryManager alloc] initWithHosts:[hostList allObjects] andCallback:self];
|
||||||
|
|
||||||
|
[[NSNotificationCenter defaultCenter] addObserver: self
|
||||||
|
selector: @selector(handleReturnToForeground)
|
||||||
|
name: UIApplicationWillEnterForegroundNotification
|
||||||
|
object: nil];
|
||||||
|
|
||||||
[self updateHosts];
|
[self updateHosts];
|
||||||
[self.view addSubview:hostScrollView];
|
[self.view addSubview:hostScrollView];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-(void)dealloc
|
||||||
|
{
|
||||||
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)handleReturnToForeground
|
||||||
|
{
|
||||||
|
// This will refresh the applist
|
||||||
|
if (_selectedHost != nil) {
|
||||||
|
[self hostClicked:_selectedHost view:nil];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
- (void)viewDidAppear:(BOOL)animated
|
- (void)viewDidAppear:(BOOL)animated
|
||||||
{
|
{
|
||||||
[super viewDidAppear:animated];
|
[super viewDidAppear:animated];
|
||||||
@@ -371,10 +582,7 @@ static NSArray* appList;
|
|||||||
|
|
||||||
[_discMan startDiscovery];
|
[_discMan startDiscovery];
|
||||||
|
|
||||||
// This will refresh the applist
|
[self handleReturnToForeground];
|
||||||
if (_selectedHost != nil) {
|
|
||||||
[self hostClicked:_selectedHost];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)viewDidDisappear:(BOOL)animated
|
- (void)viewDidDisappear:(BOOL)animated
|
||||||
@@ -383,8 +591,11 @@ static NSArray* appList;
|
|||||||
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
|
// when discovery stops, we must create a new instance because you cannot restart an NSOperation when it is finished
|
||||||
[_discMan stopDiscovery];
|
[_discMan stopDiscovery];
|
||||||
|
|
||||||
|
// Purge the box art cache
|
||||||
|
[_boxArtCache removeAllObjects];
|
||||||
|
|
||||||
// In case the host objects were updated in the background
|
// In case the host objects were updated in the background
|
||||||
[[[DataManager alloc] init] saveHosts];
|
[[[DataManager alloc] init] saveData];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) retrieveSavedHosts {
|
- (void) retrieveSavedHosts {
|
||||||
@@ -392,6 +603,19 @@ static NSArray* appList;
|
|||||||
NSArray* hosts = [dataMan retrieveHosts];
|
NSArray* hosts = [dataMan retrieveHosts];
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList addObjectsFromArray:hosts];
|
[hostList addObjectsFromArray:hosts];
|
||||||
|
|
||||||
|
// Initialize the non-persistent host state
|
||||||
|
for (Host* host in hostList) {
|
||||||
|
if (host.activeAddress == nil) {
|
||||||
|
host.activeAddress = host.localAddress;
|
||||||
|
}
|
||||||
|
if (host.activeAddress == nil) {
|
||||||
|
host.activeAddress = host.externalAddress;
|
||||||
|
}
|
||||||
|
if (host.activeAddress == nil) {
|
||||||
|
host.activeAddress = host.address;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -399,7 +623,7 @@ static NSArray* appList;
|
|||||||
dispatch_async(dispatch_get_main_queue(), ^{
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
Log(LOG_D, @"New host list:");
|
Log(LOG_D, @"New host list:");
|
||||||
for (Host* host in hosts) {
|
for (Host* host in hosts) {
|
||||||
Log(LOG_D, @"Host: \n{\n\t name:%@ \n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online);
|
Log(LOG_D, @"Host: \n{\n\t name:%@ \n\t address:%@ \n\t localAddress:%@ \n\t externalAddress:%@ \n\t uuid:%@ \n\t mac:%@ \n\t pairState:%d \n\t online:%d \n\t activeAddress:%@ \n}", host.name, host.address, host.localAddress, host.externalAddress, host.uuid, host.mac, host.pairState, host.online, host.activeAddress);
|
||||||
}
|
}
|
||||||
@synchronized(hostList) {
|
@synchronized(hostList) {
|
||||||
[hostList removeAllObjects];
|
[hostList removeAllObjects];
|
||||||
@@ -416,13 +640,16 @@ static NSArray* appList;
|
|||||||
UIComputerView* compView;
|
UIComputerView* compView;
|
||||||
float prevEdge = -1;
|
float prevEdge = -1;
|
||||||
@synchronized (hostList) {
|
@synchronized (hostList) {
|
||||||
for (Host* comp in hostList) {
|
// Sort the host list in alphabetical order
|
||||||
|
NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)];
|
||||||
|
for (Host* comp in sortedHostList) {
|
||||||
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
|
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
|
||||||
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
|
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
|
||||||
prevEdge = compView.frame.origin.x + compView.frame.size.width;
|
prevEdge = compView.frame.origin.x + compView.frame.size.width;
|
||||||
[hostScrollView addSubview:compView];
|
[hostScrollView addSubview:compView];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
|
prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
|
||||||
addComp.center = CGPointMake(prevEdge, hostScrollView.frame.size.height / 2);
|
addComp.center = CGPointMake(prevEdge, hostScrollView.frame.size.height / 2);
|
||||||
|
|
||||||
@@ -438,7 +665,66 @@ static NSArray* appList;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) updateApps {
|
// This function forces immediate decoding of the UIImage, rather
|
||||||
|
// than the default lazy decoding that results in janky scrolling.
|
||||||
|
+ (UIImage*) loadBoxArtForCaching:(App*)app {
|
||||||
|
|
||||||
|
CGImageSourceRef source = CGImageSourceCreateWithData((__bridge CFDataRef)app.image, NULL);
|
||||||
|
CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, (__bridge CFDictionaryRef)@{(id)kCGImageSourceShouldCacheImmediately: (id)kCFBooleanTrue});
|
||||||
|
|
||||||
|
UIImage *boxArt = [UIImage imageWithCGImage:cgImage];
|
||||||
|
|
||||||
|
CGImageRelease(cgImage);
|
||||||
|
CFRelease(source);
|
||||||
|
|
||||||
|
return boxArt;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateBoxArtCacheForApp:(App*)app {
|
||||||
|
if (app.image == nil) {
|
||||||
|
[_boxArtCache removeObjectForKey:app];
|
||||||
|
}
|
||||||
|
else if ([_boxArtCache objectForKey:app] == nil) {
|
||||||
|
[_boxArtCache setObject:[MainFrameViewController loadBoxArtForCaching:app] forKey:app];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) updateAppsForHost:(Host*)host {
|
||||||
|
if (host != _selectedHost) {
|
||||||
|
Log(LOG_W, @"Mismatched host during app update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_sortedAppList = [host.appList allObjects];
|
||||||
|
_sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
|
||||||
|
|
||||||
|
// Split the sorted array in half to allow 2 jobs to process app assets at once
|
||||||
|
NSArray *firstHalf;
|
||||||
|
NSArray *secondHalf;
|
||||||
|
NSRange range;
|
||||||
|
|
||||||
|
range.location = 0;
|
||||||
|
range.length = [_sortedAppList count] / 2;
|
||||||
|
|
||||||
|
firstHalf = [_sortedAppList subarrayWithRange:range];
|
||||||
|
|
||||||
|
range.location = range.length;
|
||||||
|
range.length = [_sortedAppList count] - range.length;
|
||||||
|
|
||||||
|
secondHalf = [_sortedAppList subarrayWithRange:range];
|
||||||
|
|
||||||
|
// Start 2 jobs
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
for (App* app in firstHalf) {
|
||||||
|
[self updateBoxArtCacheForApp:app];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||||
|
for (App* app in secondHalf) {
|
||||||
|
[self updateBoxArtCacheForApp:app];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
[hostScrollView removeFromSuperview];
|
[hostScrollView removeFromSuperview];
|
||||||
[self.collectionView reloadData];
|
[self.collectionView reloadData];
|
||||||
}
|
}
|
||||||
@@ -446,8 +732,8 @@ static NSArray* appList;
|
|||||||
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
||||||
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
|
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
|
||||||
|
|
||||||
App* app = appList[indexPath.row];
|
App* app = _sortedAppList[indexPath.row];
|
||||||
UIAppView* appView = [[UIAppView alloc] initWithApp:app andCallback:self];
|
UIAppView* appView = [[UIAppView alloc] initWithApp:app cache:_boxArtCache andCallback:self];
|
||||||
[appView updateAppImage];
|
[appView updateAppImage];
|
||||||
|
|
||||||
if (appView.bounds.size.width > 10.0) {
|
if (appView.bounds.size.width > 10.0) {
|
||||||
@@ -458,7 +744,19 @@ static NSArray* appList;
|
|||||||
|
|
||||||
[cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
|
[cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
|
||||||
[cell addSubview:appView];
|
[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;
|
return cell;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -467,7 +765,12 @@ static NSArray* appList;
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
||||||
return appList.count;
|
if (_selectedHost != nil) {
|
||||||
|
return _selectedHost.appList.count;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void)didReceiveMemoryWarning
|
- (void)didReceiveMemoryWarning
|
||||||
@@ -489,4 +792,12 @@ static NSArray* appList;
|
|||||||
return YES;
|
return YES;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) disableNavigation {
|
||||||
|
self.navigationController.navigationBar.topItem.rightBarButtonItem.enabled = NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void) enableNavigation {
|
||||||
|
self.navigationController.navigationBar.topItem.rightBarButtonItem.enabled = YES;
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -554,8 +554,8 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1
|
|||||||
UITouch *touch = [touches anyObject];
|
UITouch *touch = [touches anyObject];
|
||||||
CGPoint nowPoint = [touch locationInView:self.view];
|
CGPoint nowPoint = [touch locationInView:self.view];
|
||||||
|
|
||||||
if (abs(nowPoint.x - _beginPoint.x) > kDirectionPanThreshold) _dragging = YES;
|
if (fabs(nowPoint.x - _beginPoint.x) > kDirectionPanThreshold) _dragging = YES;
|
||||||
else if (abs(nowPoint.y - _beginPoint.y) > kDirectionPanThreshold) self.state = UIGestureRecognizerStateFailed;
|
else if (fabs(nowPoint.y - _beginPoint.y) > kDirectionPanThreshold) self.state = UIGestureRecognizerStateFailed;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
@@ -742,15 +742,6 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
_userInteractionStore = _contentView.userInteractionEnabled;
|
_userInteractionStore = _contentView.userInteractionEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
- (NSUInteger)supportedInterfaceOrientations
|
|
||||||
{
|
|
||||||
// we could have simply not implemented this, but we choose to call super to make explicit that we
|
|
||||||
// want the default behavior.
|
|
||||||
return [super supportedInterfaceOrientations];
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#pragma mark - Public methods and property accessors
|
#pragma mark - Public methods and property accessors
|
||||||
|
|
||||||
- (void)setFrontViewController:(UIViewController *)frontViewController
|
- (void)setFrontViewController:(UIViewController *)frontViewController
|
||||||
@@ -1274,7 +1265,7 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
NSTimeInterval duration = _toggleAnimationDuration;
|
NSTimeInterval duration = _toggleAnimationDuration;
|
||||||
|
|
||||||
// Velocity driven change:
|
// Velocity driven change:
|
||||||
if (fabsf(velocity) > _quickFlickVelocity)
|
if (fabs(velocity) > _quickFlickVelocity)
|
||||||
{
|
{
|
||||||
// we may need to set the drag position and to adjust the animation duration
|
// we may need to set the drag position and to adjust the animation duration
|
||||||
CGFloat journey = xLocation;
|
CGFloat journey = xLocation;
|
||||||
@@ -1292,7 +1283,7 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
duration = fabsf(journey/velocity);
|
duration = fabs(journey/velocity);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Position driven change:
|
// Position driven change:
|
||||||
@@ -1349,7 +1340,7 @@ const int FrontViewPositionNone = 0xff;
|
|||||||
|
|
||||||
NSTimeInterval duration = animated?_toggleAnimationDuration:0.0;
|
NSTimeInterval duration = animated?_toggleAnimationDuration:0.0;
|
||||||
NSTimeInterval firstDuration = duration;
|
NSTimeInterval firstDuration = duration;
|
||||||
int initialPosDif = abs( _frontViewPosition - preReplacementPosition );
|
int initialPosDif = (int) labs( _frontViewPosition - preReplacementPosition );
|
||||||
if ( initialPosDif == 1 ) firstDuration *= 0.8;
|
if ( initialPosDif == 1 ) firstDuration *= 0.8;
|
||||||
else if ( initialPosDif == 0 ) firstDuration = 0;
|
else if ( initialPosDif == 0 ) firstDuration = 0;
|
||||||
|
|
||||||
|
|||||||
@@ -33,18 +33,44 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
|||||||
} else if ([currentSettings.height integerValue] == 1080) {
|
} else if ([currentSettings.height integerValue] == 1080) {
|
||||||
resolution = 1;
|
resolution = 1;
|
||||||
} else {
|
} else {
|
||||||
resolution = 2;
|
resolution = 0;
|
||||||
}
|
}
|
||||||
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
|
NSInteger onscreenControls = [currentSettings.onscreenControls integerValue];
|
||||||
|
|
||||||
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
[self.resolutionSelector setSelectedSegmentIndex:resolution];
|
||||||
|
[self.resolutionSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||||
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
[self.framerateSelector setSelectedSegmentIndex:framerate];
|
||||||
|
[self.framerateSelector addTarget:self action:@selector(newResolutionFpsChosen) forControlEvents:UIControlEventValueChanged];
|
||||||
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
[self.onscreenControlSelector setSelectedSegmentIndex:onscreenControls];
|
||||||
[self.bitrateSlider setValue:(_bitrate / BITRATE_INTERVAL) animated:YES];
|
[self.bitrateSlider setValue:(_bitrate / BITRATE_INTERVAL) animated:YES];
|
||||||
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
[self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged];
|
||||||
[self updateBitrateText];
|
[self updateBitrateText];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void) newResolutionFpsChosen {
|
||||||
|
NSInteger frameRate = [self getChosenFrameRate];
|
||||||
|
NSInteger resHeight = [self getChosenStreamHeight];
|
||||||
|
NSInteger defaultBitrate;
|
||||||
|
|
||||||
|
// 1080p60 is 20 Mbps
|
||||||
|
if (frameRate == 60 && resHeight == 1080) {
|
||||||
|
defaultBitrate = 20000;
|
||||||
|
}
|
||||||
|
// 720p60 and 1080p30 are 10 Mbps
|
||||||
|
else if (frameRate == 60 || resHeight == 1080) {
|
||||||
|
defaultBitrate = 10000;
|
||||||
|
}
|
||||||
|
// 720p30 is 5 Mbps
|
||||||
|
else {
|
||||||
|
defaultBitrate = 5000;
|
||||||
|
}
|
||||||
|
|
||||||
|
_bitrate = defaultBitrate;
|
||||||
|
[self.bitrateSlider setValue:defaultBitrate / BITRATE_INTERVAL animated:YES];
|
||||||
|
|
||||||
|
[self updateBitrateText];
|
||||||
|
}
|
||||||
|
|
||||||
- (void) bitrateSliderMoved {
|
- (void) bitrateSliderMoved {
|
||||||
_bitrate = BITRATE_INTERVAL * (int)self.bitrateSlider.value;
|
_bitrate = BITRATE_INTERVAL * (int)self.bitrateSlider.value;
|
||||||
[self updateBitrateText];
|
[self updateBitrateText];
|
||||||
@@ -55,25 +81,23 @@ static NSString* bitrateFormat = @"Bitrate: %.1f Mbps";
|
|||||||
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, _bitrate / 1000.]];
|
[self.bitrateLabel setText:[NSString stringWithFormat:bitrateFormat, _bitrate / 1000.]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSInteger) getChosenFrameRate {
|
||||||
|
return [self.framerateSelector selectedSegmentIndex] == 0 ? 30 : 60;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger) getChosenStreamHeight {
|
||||||
|
return [self.resolutionSelector selectedSegmentIndex] == 0 ? 720 : 1080;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSInteger) getChosenStreamWidth {
|
||||||
|
return [self getChosenStreamHeight] == 720 ? 1280 : 1920;
|
||||||
|
}
|
||||||
|
|
||||||
- (void) saveSettings {
|
- (void) saveSettings {
|
||||||
DataManager* dataMan = [[DataManager alloc] init];
|
DataManager* dataMan = [[DataManager alloc] init];
|
||||||
NSInteger framerate = [self.framerateSelector selectedSegmentIndex] == 0 ? 30 : 60;
|
NSInteger framerate = [self getChosenFrameRate];
|
||||||
NSInteger height;
|
NSInteger height = [self getChosenStreamHeight];
|
||||||
NSInteger width;
|
NSInteger width = [self getChosenStreamWidth];
|
||||||
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 onscreenControls = [self.onscreenControlSelector selectedSegmentIndex];
|
NSInteger onscreenControls = [self.onscreenControlSelector selectedSegmentIndex];
|
||||||
[dataMan saveSettingsWithBitrate:_bitrate framerate:framerate height:height width:width onscreenControls:onscreenControls];
|
[dataMan saveSettingsWithBitrate:_bitrate framerate:framerate height:height width:width onscreenControls:onscreenControls];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,24 +102,34 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
- (void) stageFailed:(char*)stageName withError:(long)errorCode {
|
- (void) stageFailed:(char*)stageName withError:(long)errorCode {
|
||||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
Log(LOG_I, @"Stage %s failed: %ld", stageName, errorCode);
|
||||||
message:[NSString stringWithFormat:@"%s failed with error %ld",
|
|
||||||
stageName, errorCode]
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
message:[NSString stringWithFormat:@"%s failed with error %ld",
|
||||||
[self returnToMainFrame];
|
stageName, errorCode]
|
||||||
}]];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[self presentViewController:alert animated:YES completion:nil];
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
|
[self returnToMainFrame];
|
||||||
|
}]];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
});
|
||||||
|
|
||||||
|
[_streamMan stopStreamInternal];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) launchFailed:(NSString*)message {
|
- (void) launchFailed:(NSString*)message {
|
||||||
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
Log(LOG_I, @"Launch failed: %@", message);
|
||||||
message:message
|
|
||||||
preferredStyle:UIAlertControllerStyleAlert];
|
dispatch_async(dispatch_get_main_queue(), ^{
|
||||||
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Connection Failed"
|
||||||
[self returnToMainFrame];
|
message:message
|
||||||
}]];
|
preferredStyle:UIAlertControllerStyleAlert];
|
||||||
[self presentViewController:alert animated:YES completion:nil];
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||||
|
[self returnToMainFrame];
|
||||||
|
}]];
|
||||||
|
[self presentViewController:alert animated:YES completion:nil];
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
- (void) displayMessage:(char*)message {
|
- (void) displayMessage:(char*)message {
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>CFBundleDevelopmentRegion</key>
|
|
||||||
<string>en</string>
|
|
||||||
<key>CFBundleExecutable</key>
|
|
||||||
<string>${EXECUTABLE_NAME}</string>
|
|
||||||
<key>CFBundleIdentifier</key>
|
|
||||||
<string>com.limelight-stream.${PRODUCT_NAME:rfc1034identifier}</string>
|
|
||||||
<key>CFBundleInfoDictionaryVersion</key>
|
|
||||||
<string>6.0</string>
|
|
||||||
<key>CFBundlePackageType</key>
|
|
||||||
<string>BNDL</string>
|
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>1.0</string>
|
|
||||||
<key>CFBundleSignature</key>
|
|
||||||
<string>????</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>1</string>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
//
|
|
||||||
// MoonlightTests.m
|
|
||||||
// MoonlightTests
|
|
||||||
//
|
|
||||||
// Created by Diego Waxemberg on 8/30/14.
|
|
||||||
// Copyright (c) 2014 Moonlight Stream. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#import <XCTest/XCTest.h>
|
|
||||||
|
|
||||||
@interface LimelightTests : XCTestCase
|
|
||||||
|
|
||||||
@end
|
|
||||||
|
|
||||||
@implementation LimelightTests
|
|
||||||
|
|
||||||
- (void)setUp
|
|
||||||
{
|
|
||||||
[super setUp];
|
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)tearDown
|
|
||||||
{
|
|
||||||
// Put teardown code here. This method is called after the invocation of each test method in the class.
|
|
||||||
[super tearDown];
|
|
||||||
}
|
|
||||||
|
|
||||||
- (void)testExample
|
|
||||||
{
|
|
||||||
XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
|
|
||||||
}
|
|
||||||
|
|
||||||
@end
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
/* Localized versions of Info.plist keys */
|
|
||||||
|
|
||||||
@@ -3,10 +3,11 @@
|
|||||||
archiveVersion = 1;
|
archiveVersion = 1;
|
||||||
classes = {
|
classes = {
|
||||||
};
|
};
|
||||||
objectVersion = 46;
|
objectVersion = 47;
|
||||||
objects = {
|
objects = {
|
||||||
|
|
||||||
/* Begin PBXBuildFile section */
|
/* 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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
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 */; };
|
FB290CF219B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; };
|
||||||
FB290CF419B2C406004C83CF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF319B2C406004C83CF /* CoreGraphics.framework */; };
|
FB290CF419B2C406004C83CF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF319B2C406004C83CF /* CoreGraphics.framework */; };
|
||||||
FB290CF619B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
|
FB290CF619B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
|
||||||
@@ -24,11 +27,6 @@
|
|||||||
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0319B2C406004C83CF /* AppDelegate.m */; };
|
FB290D0419B2C406004C83CF /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0319B2C406004C83CF /* AppDelegate.m */; };
|
||||||
FB290D0719B2C406004C83CF /* Limelight.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */; };
|
FB290D0719B2C406004C83CF /* Limelight.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */; };
|
||||||
FB290D0919B2C406004C83CF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FB290D0819B2C406004C83CF /* Images.xcassets */; };
|
FB290D0919B2C406004C83CF /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FB290D0819B2C406004C83CF /* Images.xcassets */; };
|
||||||
FB290D1119B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; };
|
|
||||||
FB290D1219B2C406004C83CF /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF519B2C406004C83CF /* UIKit.framework */; };
|
|
||||||
FB290D1319B2C406004C83CF /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF719B2C406004C83CF /* CoreData.framework */; };
|
|
||||||
FB290D1B19B2C406004C83CF /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FB290D1919B2C406004C83CF /* InfoPlist.strings */; };
|
|
||||||
FB290D1D19B2C406004C83CF /* LimelightTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FB290D1C19B2C406004C83CF /* LimelightTests.m */; };
|
|
||||||
FB290DB719B2C870004C83CF /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB619B2C870004C83CF /* libz.dylib */; };
|
FB290DB719B2C870004C83CF /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB619B2C870004C83CF /* libz.dylib */; };
|
||||||
FB290DB919B2C877004C83CF /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB819B2C877004C83CF /* libbz2.dylib */; };
|
FB290DB919B2C877004C83CF /* libbz2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DB819B2C877004C83CF /* libbz2.dylib */; };
|
||||||
FB290DC419B2E98F004C83CF /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DC319B2E98F004C83CF /* libxml2.dylib */; };
|
FB290DC419B2E98F004C83CF /* libxml2.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290DC319B2E98F004C83CF /* libxml2.dylib */; };
|
||||||
@@ -39,6 +37,7 @@
|
|||||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
|
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4678FE1A565DAC00377732 /* WakeOnLanManager.m */; };
|
||||||
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
|
FB4679011A57048000377732 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB4679001A57048000377732 /* CoreFoundation.framework */; };
|
||||||
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FB4A23B71A9D3637004D2EF2 /* LoadingFrameViewController.m */; };
|
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 */; };
|
FB6549561A57907E001C8F39 /* DiscoveryWorker.m in Sources */ = {isa = PBXBuildFile; fileRef = FB6549551A57907E001C8F39 /* DiscoveryWorker.m */; };
|
||||||
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
|
FB7E794419C8B71B00A15F68 /* libiconv.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FB7E794319C8B71B00A15F68 /* libiconv.dylib */; };
|
||||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
|
FB89462819F646E200339C8A /* CryptoManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FB89460619F646E200339C8A /* CryptoManager.m */; };
|
||||||
@@ -70,12 +69,12 @@
|
|||||||
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; };
|
FBD3494319FC9C04002D2A60 /* AppAssetManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494219FC9C04002D2A60 /* AppAssetManager.m */; };
|
||||||
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
|
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; };
|
||||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
|
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; };
|
||||||
FBD3495B1A004411002D2A60 /* Host.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495A1A004411002D2A60 /* Host.m */; };
|
|
||||||
FBD3495E1A004412002D2A60 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495D1A004412002D2A60 /* Settings.m */; };
|
FBD3495E1A004412002D2A60 /* Settings.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495D1A004412002D2A60 /* Settings.m */; };
|
||||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD349611A0089F6002D2A60 /* DataManager.m */; };
|
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD349611A0089F6002D2A60 /* DataManager.m */; };
|
||||||
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86DF19F7A837001C18A8 /* UIComputerView.m */; };
|
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86DF19F7A837001C18A8 /* UIComputerView.m */; };
|
||||||
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E519F82297001C18A8 /* UIAppView.m */; };
|
FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E519F82297001C18A8 /* UIAppView.m */; };
|
||||||
FBDE86E919F82315001C18A8 /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E819F82315001C18A8 /* App.m */; };
|
FBFCB3311B50B29400089F8A /* Host.m in Sources */ = {isa = PBXBuildFile; fileRef = FBFCB3301B50B29400089F8A /* Host.m */; };
|
||||||
|
FBFCB3351B50B29400089F8A /* App.m in Sources */ = {isa = PBXBuildFile; fileRef = FBFCB3341B50B29400089F8A /* App.m */; };
|
||||||
/* End PBXBuildFile section */
|
/* End PBXBuildFile section */
|
||||||
|
|
||||||
/* Begin PBXContainerItemProxy section */
|
/* Begin PBXContainerItemProxy section */
|
||||||
@@ -93,16 +92,11 @@
|
|||||||
remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
|
remoteGlobalIDString = FB290E2E19B37A4E004C83CF;
|
||||||
remoteInfo = "moonlight-common";
|
remoteInfo = "moonlight-common";
|
||||||
};
|
};
|
||||||
FB290D1419B2C406004C83CF /* PBXContainerItemProxy */ = {
|
|
||||||
isa = PBXContainerItemProxy;
|
|
||||||
containerPortal = FB290CE619B2C406004C83CF /* Project object */;
|
|
||||||
proxyType = 1;
|
|
||||||
remoteGlobalIDString = FB290CED19B2C406004C83CF;
|
|
||||||
remoteInfo = Limelight;
|
|
||||||
};
|
|
||||||
/* End PBXContainerItemProxy section */
|
/* End PBXContainerItemProxy section */
|
||||||
|
|
||||||
/* Begin PBXFileReference 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>"; };
|
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>"; };
|
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>"; };
|
9E5D5FF91A5A5A3900689918 /* Roboto-Black.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Black.ttf"; sourceTree = "<group>"; };
|
||||||
@@ -111,6 +105,10 @@
|
|||||||
9E5D60001A5A5A3900689918 /* Roboto-Medium.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Roboto-Medium.ttf"; sourceTree = "<group>"; };
|
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>"; };
|
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>"; };
|
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; };
|
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; };
|
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; };
|
FB290CF319B2C406004C83CF /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
|
||||||
@@ -124,10 +122,6 @@
|
|||||||
FB290D0319B2C406004C83CF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
FB290D0319B2C406004C83CF /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
|
||||||
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Limelight.xcdatamodel; sourceTree = "<group>"; };
|
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Limelight.xcdatamodel; sourceTree = "<group>"; };
|
||||||
FB290D0819B2C406004C83CF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
FB290D0819B2C406004C83CF /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = "<group>"; };
|
||||||
FB290D0E19B2C406004C83CF /* LimelightTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LimelightTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
|
||||||
FB290D1819B2C406004C83CF /* LimelightTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "LimelightTests-Info.plist"; sourceTree = "<group>"; };
|
|
||||||
FB290D1A19B2C406004C83CF /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = "<group>"; };
|
|
||||||
FB290D1C19B2C406004C83CF /* LimelightTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LimelightTests.m; sourceTree = "<group>"; };
|
|
||||||
FB290DB619B2C870004C83CF /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
FB290DB619B2C870004C83CF /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
|
||||||
FB290DB819B2C877004C83CF /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; };
|
FB290DB819B2C877004C83CF /* libbz2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbz2.dylib; path = usr/lib/libbz2.dylib; sourceTree = SDKROOT; };
|
||||||
FB290DC319B2E98F004C83CF /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
|
FB290DC319B2E98F004C83CF /* libxml2.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libxml2.dylib; path = usr/lib/libxml2.dylib; sourceTree = SDKROOT; };
|
||||||
@@ -143,6 +137,9 @@
|
|||||||
FB4679001A57048000377732 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
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>"; };
|
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Limelight 0.3.1.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
@@ -273,6 +270,7 @@
|
|||||||
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
|
FB9AFD3F1A7E127D00872C98 /* AppListResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppListResponse.m; sourceTree = "<group>"; };
|
||||||
FB9AFD411A7F0C6900872C98 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
FB9AFD411A7F0C6900872C98 /* Controller.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Controller.h; sourceTree = "<group>"; };
|
||||||
FB9AFD421A7F0C6900872C98 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
FB9AFD421A7F0C6900872C98 /* Controller.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Controller.m; sourceTree = "<group>"; };
|
||||||
|
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Moonlight v1.0.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
FBD1C8E01A8AD69E00C6703C /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logger.h; sourceTree = "<group>"; };
|
FBD1C8E01A8AD69E00C6703C /* Logger.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Logger.h; sourceTree = "<group>"; };
|
||||||
FBD1C8E11A8AD71400C6703C /* Logger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Logger.m; sourceTree = "<group>"; };
|
FBD1C8E11A8AD71400C6703C /* Logger.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Logger.m; sourceTree = "<group>"; };
|
||||||
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
|
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppAssetManager.h; sourceTree = "<group>"; };
|
||||||
@@ -282,8 +280,6 @@
|
|||||||
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; };
|
FBD3495119FF36FB002D2A60 /* SWRevealViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SWRevealViewController.h; sourceTree = "<group>"; };
|
||||||
FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = "<group>"; };
|
FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = "<group>"; };
|
||||||
FBD349571A003F05002D2A60 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
FBD349571A003F05002D2A60 /* libsqlite3.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libsqlite3.dylib; path = usr/lib/libsqlite3.dylib; sourceTree = SDKROOT; };
|
||||||
FBD349591A004411002D2A60 /* Host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Host.h; path = Database/Host.h; sourceTree = "<group>"; };
|
|
||||||
FBD3495A1A004411002D2A60 /* Host.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Host.m; path = Database/Host.m; sourceTree = "<group>"; };
|
|
||||||
FBD3495C1A004412002D2A60 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Settings.h; path = Database/Settings.h; sourceTree = "<group>"; };
|
FBD3495C1A004412002D2A60 /* Settings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Settings.h; path = Database/Settings.h; sourceTree = "<group>"; };
|
||||||
FBD3495D1A004412002D2A60 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Settings.m; path = Database/Settings.m; sourceTree = "<group>"; };
|
FBD3495D1A004412002D2A60 /* Settings.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Settings.m; path = Database/Settings.m; sourceTree = "<group>"; };
|
||||||
FBD349601A0089F6002D2A60 /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataManager.h; path = Database/DataManager.h; sourceTree = "<group>"; };
|
FBD349601A0089F6002D2A60 /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataManager.h; path = Database/DataManager.h; sourceTree = "<group>"; };
|
||||||
@@ -292,8 +288,12 @@
|
|||||||
FBDE86DF19F7A837001C18A8 /* UIComputerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIComputerView.m; sourceTree = "<group>"; };
|
FBDE86DF19F7A837001C18A8 /* UIComputerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIComputerView.m; sourceTree = "<group>"; };
|
||||||
FBDE86E419F82297001C18A8 /* UIAppView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAppView.h; sourceTree = "<group>"; };
|
FBDE86E419F82297001C18A8 /* UIAppView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAppView.h; sourceTree = "<group>"; };
|
||||||
FBDE86E519F82297001C18A8 /* UIAppView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAppView.m; sourceTree = "<group>"; };
|
FBDE86E519F82297001C18A8 /* UIAppView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAppView.m; sourceTree = "<group>"; };
|
||||||
FBDE86E719F82315001C18A8 /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = ../App.h; sourceTree = "<group>"; };
|
FBFCB32E1B50B29400089F8A /* Host+CoreDataProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "Host+CoreDataProperties.h"; path = "Database/Host+CoreDataProperties.h"; sourceTree = "<group>"; };
|
||||||
FBDE86E819F82315001C18A8 /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = App.m; path = ../App.m; sourceTree = "<group>"; };
|
FBFCB32F1B50B29400089F8A /* Host.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Host.h; path = Database/Host.h; sourceTree = "<group>"; };
|
||||||
|
FBFCB3301B50B29400089F8A /* Host.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = Host.m; path = Database/Host.m; sourceTree = "<group>"; };
|
||||||
|
FBFCB3321B50B29400089F8A /* App+CoreDataProperties.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "App+CoreDataProperties.h"; path = "Database/App+CoreDataProperties.h"; sourceTree = "<group>"; };
|
||||||
|
FBFCB3331B50B29400089F8A /* App.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = App.h; path = Database/App.h; sourceTree = "<group>"; };
|
||||||
|
FBFCB3341B50B29400089F8A /* App.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = App.m; path = Database/App.m; sourceTree = "<group>"; };
|
||||||
/* End PBXFileReference section */
|
/* End PBXFileReference section */
|
||||||
|
|
||||||
/* Begin PBXFrameworksBuildPhase section */
|
/* Begin PBXFrameworksBuildPhase section */
|
||||||
@@ -317,16 +317,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
FB290D0B19B2C406004C83CF /* Frameworks */ = {
|
|
||||||
isa = PBXFrameworksBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
FB290D1319B2C406004C83CF /* CoreData.framework in Frameworks */,
|
|
||||||
FB290D1219B2C406004C83CF /* UIKit.framework in Frameworks */,
|
|
||||||
FB290D1119B2C406004C83CF /* Foundation.framework in Frameworks */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXFrameworksBuildPhase section */
|
/* End PBXFrameworksBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXGroup section */
|
/* Begin PBXGroup section */
|
||||||
@@ -365,7 +355,6 @@
|
|||||||
children = (
|
children = (
|
||||||
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */,
|
98A03B4519F3514B00861ACA /* moonlight-common.xcodeproj */,
|
||||||
FB290CF919B2C406004C83CF /* Limelight */,
|
FB290CF919B2C406004C83CF /* Limelight */,
|
||||||
FB290D1619B2C406004C83CF /* LimelightTests */,
|
|
||||||
FB290CF019B2C406004C83CF /* Frameworks */,
|
FB290CF019B2C406004C83CF /* Frameworks */,
|
||||||
FB290CEF19B2C406004C83CF /* Products */,
|
FB290CEF19B2C406004C83CF /* Products */,
|
||||||
);
|
);
|
||||||
@@ -375,7 +364,6 @@
|
|||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FB290CEE19B2C406004C83CF /* Moonlight.app */,
|
FB290CEE19B2C406004C83CF /* Moonlight.app */,
|
||||||
FB290D0E19B2C406004C83CF /* LimelightTests.xctest */,
|
|
||||||
);
|
);
|
||||||
name = Products;
|
name = Products;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -422,6 +410,10 @@
|
|||||||
FB89463719F6473800339C8A /* Launch Screen.xib */,
|
FB89463719F6473800339C8A /* Launch Screen.xib */,
|
||||||
FB290D0819B2C406004C83CF /* Images.xcassets */,
|
FB290D0819B2C406004C83CF /* Images.xcassets */,
|
||||||
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */,
|
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */,
|
||||||
|
FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */,
|
||||||
|
FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */,
|
||||||
|
FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */,
|
||||||
|
FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */,
|
||||||
);
|
);
|
||||||
path = Limelight;
|
path = Limelight;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -437,24 +429,6 @@
|
|||||||
name = "Supporting Files";
|
name = "Supporting Files";
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB290D1619B2C406004C83CF /* LimelightTests */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
FB290D1C19B2C406004C83CF /* LimelightTests.m */,
|
|
||||||
FB290D1719B2C406004C83CF /* Supporting Files */,
|
|
||||||
);
|
|
||||||
path = LimelightTests;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
FB290D1719B2C406004C83CF /* Supporting Files */ = {
|
|
||||||
isa = PBXGroup;
|
|
||||||
children = (
|
|
||||||
FB290D1819B2C406004C83CF /* LimelightTests-Info.plist */,
|
|
||||||
FB290D1919B2C406004C83CF /* InfoPlist.strings */,
|
|
||||||
);
|
|
||||||
name = "Supporting Files";
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
FB89460419F646E200339C8A /* Crypto */ = {
|
FB89460419F646E200339C8A /* Crypto */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@@ -462,6 +436,8 @@
|
|||||||
FB89460619F646E200339C8A /* CryptoManager.m */,
|
FB89460619F646E200339C8A /* CryptoManager.m */,
|
||||||
FB89460719F646E200339C8A /* mkcert.c */,
|
FB89460719F646E200339C8A /* mkcert.c */,
|
||||||
FB89460819F646E200339C8A /* mkcert.h */,
|
FB89460819F646E200339C8A /* mkcert.h */,
|
||||||
|
FB53E1411BE5DC4400CD6ECE /* IdManager.h */,
|
||||||
|
FB53E1421BE5DC4400CD6ECE /* IdManager.m */,
|
||||||
);
|
);
|
||||||
path = Crypto;
|
path = Crypto;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -486,7 +462,7 @@
|
|||||||
children = (
|
children = (
|
||||||
FB9AFD2F1A7C979700872C98 /* Http */,
|
FB9AFD2F1A7C979700872C98 /* Http */,
|
||||||
FB9AFD341A7D877B00872C98 /* Discovery */,
|
FB9AFD341A7D877B00872C98 /* Discovery */,
|
||||||
FB9AFD331A7D876F00872C98 /* AppAsset */,
|
FB9AFD331A7D876F00872C98 /* AppList */,
|
||||||
FB89461319F646E200339C8A /* PairManager.h */,
|
FB89461319F646E200339C8A /* PairManager.h */,
|
||||||
FB89461419F646E200339C8A /* PairManager.m */,
|
FB89461419F646E200339C8A /* PairManager.m */,
|
||||||
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */,
|
FB4678FD1A565DAC00377732 /* WakeOnLanManager.h */,
|
||||||
@@ -513,8 +489,6 @@
|
|||||||
FB89461E19F646E200339C8A /* Utility */ = {
|
FB89461E19F646E200339C8A /* Utility */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FBDE86E719F82315001C18A8 /* App.h */,
|
|
||||||
FBDE86E819F82315001C18A8 /* App.m */,
|
|
||||||
FB89462119F646E200339C8A /* Utils.h */,
|
FB89462119F646E200339C8A /* Utils.h */,
|
||||||
FB89462219F646E200339C8A /* Utils.m */,
|
FB89462219F646E200339C8A /* Utils.m */,
|
||||||
FBD1C8E01A8AD69E00C6703C /* Logger.h */,
|
FBD1C8E01A8AD69E00C6703C /* Logger.h */,
|
||||||
@@ -720,7 +694,7 @@
|
|||||||
name = Http;
|
name = Http;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB9AFD331A7D876F00872C98 /* AppAsset */ = {
|
FB9AFD331A7D876F00872C98 /* AppList */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */,
|
FBD3494119FC9C04002D2A60 /* AppAssetManager.h */,
|
||||||
@@ -728,7 +702,7 @@
|
|||||||
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */,
|
FB9AFD301A7D867C00872C98 /* AppAssetRetriever.h */,
|
||||||
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */,
|
FB9AFD311A7D867C00872C98 /* AppAssetRetriever.m */,
|
||||||
);
|
);
|
||||||
name = AppAsset;
|
name = AppList;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB9AFD341A7D877B00872C98 /* Discovery */ = {
|
FB9AFD341A7D877B00872C98 /* Discovery */ = {
|
||||||
@@ -747,12 +721,18 @@
|
|||||||
FBD3495F1A004453002D2A60 /* Database */ = {
|
FBD3495F1A004453002D2A60 /* Database */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
FBFCB3321B50B29400089F8A /* App+CoreDataProperties.h */,
|
||||||
|
FBFCB3331B50B29400089F8A /* App.h */,
|
||||||
|
FBFCB3341B50B29400089F8A /* App.m */,
|
||||||
|
FBFCB32E1B50B29400089F8A /* Host+CoreDataProperties.h */,
|
||||||
|
FBFCB32F1B50B29400089F8A /* Host.h */,
|
||||||
|
FBFCB3301B50B29400089F8A /* Host.m */,
|
||||||
FBD3495C1A004412002D2A60 /* Settings.h */,
|
FBD3495C1A004412002D2A60 /* Settings.h */,
|
||||||
FBD3495D1A004412002D2A60 /* Settings.m */,
|
FBD3495D1A004412002D2A60 /* Settings.m */,
|
||||||
FBD349591A004411002D2A60 /* Host.h */,
|
|
||||||
FBD3495A1A004411002D2A60 /* Host.m */,
|
|
||||||
FBD349601A0089F6002D2A60 /* DataManager.h */,
|
FBD349601A0089F6002D2A60 /* DataManager.h */,
|
||||||
FBD349611A0089F6002D2A60 /* DataManager.m */,
|
FBD349611A0089F6002D2A60 /* DataManager.m */,
|
||||||
|
9832D1341BBCD5C50036EF48 /* TemporaryApp.h */,
|
||||||
|
9832D1351BBCD5C50036EF48 /* TemporaryApp.m */,
|
||||||
);
|
);
|
||||||
name = Database;
|
name = Database;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@@ -778,43 +758,22 @@
|
|||||||
productReference = FB290CEE19B2C406004C83CF /* Moonlight.app */;
|
productReference = FB290CEE19B2C406004C83CF /* Moonlight.app */;
|
||||||
productType = "com.apple.product-type.application";
|
productType = "com.apple.product-type.application";
|
||||||
};
|
};
|
||||||
FB290D0D19B2C406004C83CF /* LimelightTests */ = {
|
|
||||||
isa = PBXNativeTarget;
|
|
||||||
buildConfigurationList = FB290D2319B2C406004C83CF /* Build configuration list for PBXNativeTarget "LimelightTests" */;
|
|
||||||
buildPhases = (
|
|
||||||
FB290D0A19B2C406004C83CF /* Sources */,
|
|
||||||
FB290D0B19B2C406004C83CF /* Frameworks */,
|
|
||||||
FB290D0C19B2C406004C83CF /* Resources */,
|
|
||||||
);
|
|
||||||
buildRules = (
|
|
||||||
);
|
|
||||||
dependencies = (
|
|
||||||
FB290D1519B2C406004C83CF /* PBXTargetDependency */,
|
|
||||||
);
|
|
||||||
name = LimelightTests;
|
|
||||||
productName = LimelightTests;
|
|
||||||
productReference = FB290D0E19B2C406004C83CF /* LimelightTests.xctest */;
|
|
||||||
productType = "com.apple.product-type.bundle.unit-test";
|
|
||||||
};
|
|
||||||
/* End PBXNativeTarget section */
|
/* End PBXNativeTarget section */
|
||||||
|
|
||||||
/* Begin PBXProject section */
|
/* Begin PBXProject section */
|
||||||
FB290CE619B2C406004C83CF /* Project object */ = {
|
FB290CE619B2C406004C83CF /* Project object */ = {
|
||||||
isa = PBXProject;
|
isa = PBXProject;
|
||||||
attributes = {
|
attributes = {
|
||||||
LastUpgradeCheck = 0510;
|
LastUpgradeCheck = 0700;
|
||||||
ORGANIZATIONNAME = "Limelight Stream";
|
ORGANIZATIONNAME = "Moonlight Stream";
|
||||||
TargetAttributes = {
|
TargetAttributes = {
|
||||||
FB290CED19B2C406004C83CF = {
|
FB290CED19B2C406004C83CF = {
|
||||||
DevelopmentTeam = DM46QST4M7;
|
DevelopmentTeam = DM46QST4M7;
|
||||||
};
|
};
|
||||||
FB290D0D19B2C406004C83CF = {
|
|
||||||
TestTargetID = FB290CED19B2C406004C83CF;
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
|
buildConfigurationList = FB290CE919B2C406004C83CF /* Build configuration list for PBXProject "Moonlight" */;
|
||||||
compatibilityVersion = "Xcode 3.2";
|
compatibilityVersion = "Xcode 6.3";
|
||||||
developmentRegion = English;
|
developmentRegion = English;
|
||||||
hasScannedForEncodings = 0;
|
hasScannedForEncodings = 0;
|
||||||
knownRegions = (
|
knownRegions = (
|
||||||
@@ -832,7 +791,6 @@
|
|||||||
projectRoot = "";
|
projectRoot = "";
|
||||||
targets = (
|
targets = (
|
||||||
FB290CED19B2C406004C83CF /* Moonlight */,
|
FB290CED19B2C406004C83CF /* Moonlight */,
|
||||||
FB290D0D19B2C406004C83CF /* LimelightTests */,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
/* End PBXProject section */
|
/* End PBXProject section */
|
||||||
@@ -867,14 +825,6 @@
|
|||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
FB290D0C19B2C406004C83CF /* Resources */ = {
|
|
||||||
isa = PBXResourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
FB290D1B19B2C406004C83CF /* InfoPlist.strings in Resources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXResourcesBuildPhase section */
|
/* End PBXResourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXSourcesBuildPhase section */
|
/* Begin PBXSourcesBuildPhase section */
|
||||||
@@ -892,21 +842,24 @@
|
|||||||
FB89462F19F646E200339C8A /* Connection.m in Sources */,
|
FB89462F19F646E200339C8A /* Connection.m in Sources */,
|
||||||
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
|
FB9AFD321A7D867C00872C98 /* AppAssetRetriever.m in Sources */,
|
||||||
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */,
|
||||||
|
FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */,
|
||||||
FB89462919F646E200339C8A /* mkcert.c in Sources */,
|
FB89462919F646E200339C8A /* mkcert.c in Sources */,
|
||||||
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */,
|
FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */,
|
||||||
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
|
FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */,
|
||||||
FBDE86E919F82315001C18A8 /* App.m in Sources */,
|
|
||||||
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */,
|
||||||
|
FBFCB3311B50B29400089F8A /* Host.m in Sources */,
|
||||||
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
|
FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */,
|
||||||
|
FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */,
|
||||||
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
|
FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */,
|
||||||
FB89462C19F646E200339C8A /* HttpManager.m in Sources */,
|
FB89462C19F646E200339C8A /* HttpManager.m in Sources */,
|
||||||
FB89462D19F646E200339C8A /* MDNSManager.m in Sources */,
|
FB89462D19F646E200339C8A /* MDNSManager.m in Sources */,
|
||||||
FB89462B19F646E200339C8A /* StreamView.m in Sources */,
|
FB89462B19F646E200339C8A /* StreamView.m in Sources */,
|
||||||
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
|
FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */,
|
||||||
FBD3495B1A004411002D2A60 /* Host.m in Sources */,
|
|
||||||
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */,
|
||||||
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
|
FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,
|
||||||
|
FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */,
|
||||||
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
|
FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */,
|
||||||
|
9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */,
|
||||||
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
FB89462819F646E200339C8A /* CryptoManager.m in Sources */,
|
||||||
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
|
FB89462E19F646E200339C8A /* PairManager.m in Sources */,
|
||||||
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
|
FB9AFD371A7E02DB00872C98 /* HttpRequest.m in Sources */,
|
||||||
@@ -918,20 +871,13 @@
|
|||||||
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
FB89462A19F646E200339C8A /* ControllerSupport.m in Sources */,
|
||||||
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
|
FB9AFD3D1A7E111600872C98 /* AppAssetResponse.m in Sources */,
|
||||||
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
FBD349621A0089F6002D2A60 /* DataManager.m in Sources */,
|
||||||
|
FBFCB3351B50B29400089F8A /* App.m in Sources */,
|
||||||
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
|
FB4A23B81A9D3637004D2EF2 /* LoadingFrameViewController.m in Sources */,
|
||||||
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
|
FB9AFD3A1A7E05CE00872C98 /* ServerInfoResponse.m in Sources */,
|
||||||
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
|
FB89463119F646E200339C8A /* StreamManager.m in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
FB290D0A19B2C406004C83CF /* Sources */ = {
|
|
||||||
isa = PBXSourcesBuildPhase;
|
|
||||||
buildActionMask = 2147483647;
|
|
||||||
files = (
|
|
||||||
FB290D1D19B2C406004C83CF /* LimelightTests.m in Sources */,
|
|
||||||
);
|
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
|
||||||
};
|
|
||||||
/* End PBXSourcesBuildPhase section */
|
/* End PBXSourcesBuildPhase section */
|
||||||
|
|
||||||
/* Begin PBXTargetDependency section */
|
/* Begin PBXTargetDependency section */
|
||||||
@@ -940,11 +886,6 @@
|
|||||||
name = "moonlight-common";
|
name = "moonlight-common";
|
||||||
targetProxy = 987140011B04541A00AB57D5 /* PBXContainerItemProxy */;
|
targetProxy = 987140011B04541A00AB57D5 /* PBXContainerItemProxy */;
|
||||||
};
|
};
|
||||||
FB290D1519B2C406004C83CF /* PBXTargetDependency */ = {
|
|
||||||
isa = PBXTargetDependency;
|
|
||||||
target = FB290CED19B2C406004C83CF /* Moonlight */;
|
|
||||||
targetProxy = FB290D1419B2C406004C83CF /* PBXContainerItemProxy */;
|
|
||||||
};
|
|
||||||
/* End PBXTargetDependency section */
|
/* End PBXTargetDependency section */
|
||||||
|
|
||||||
/* Begin PBXVariantGroup section */
|
/* Begin PBXVariantGroup section */
|
||||||
@@ -956,14 +897,6 @@
|
|||||||
name = InfoPlist.strings;
|
name = InfoPlist.strings;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
FB290D1919B2C406004C83CF /* InfoPlist.strings */ = {
|
|
||||||
isa = PBXVariantGroup;
|
|
||||||
children = (
|
|
||||||
FB290D1A19B2C406004C83CF /* en */,
|
|
||||||
);
|
|
||||||
name = InfoPlist.strings;
|
|
||||||
sourceTree = "<group>";
|
|
||||||
};
|
|
||||||
/* End PBXVariantGroup section */
|
/* End PBXVariantGroup section */
|
||||||
|
|
||||||
/* Begin XCBuildConfiguration section */
|
/* Begin XCBuildConfiguration section */
|
||||||
@@ -986,6 +919,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
COPY_PHASE_STRIP = NO;
|
COPY_PHASE_STRIP = NO;
|
||||||
|
ENABLE_TESTABILITY = YES;
|
||||||
GCC_C_LANGUAGE_STANDARD = gnu99;
|
GCC_C_LANGUAGE_STANDARD = gnu99;
|
||||||
GCC_DYNAMIC_NO_PIC = NO;
|
GCC_DYNAMIC_NO_PIC = NO;
|
||||||
GCC_OPTIMIZATION_LEVEL = 0;
|
GCC_OPTIMIZATION_LEVEL = 0;
|
||||||
@@ -1048,6 +982,7 @@
|
|||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
CODE_SIGN_IDENTITY = "iPhone Developer";
|
||||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
|
||||||
|
ENABLE_BITCODE = NO;
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
@@ -1063,6 +998,7 @@
|
|||||||
"$(PROJECT_DIR)/libs/opus/lib",
|
"$(PROJECT_DIR)/libs/opus/lib",
|
||||||
"$(PROJECT_DIR)/libs/openssl/lib",
|
"$(PROJECT_DIR)/libs/openssl/lib",
|
||||||
);
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "";
|
PROVISIONING_PROFILE = "";
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
@@ -1075,7 +1011,8 @@
|
|||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
CODE_SIGN_IDENTITY = "iPhone Developer";
|
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_PRECOMPILE_PREFIX_HEADER = YES;
|
||||||
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
||||||
HEADER_SEARCH_PATHS = (
|
HEADER_SEARCH_PATHS = (
|
||||||
@@ -1091,6 +1028,7 @@
|
|||||||
"$(PROJECT_DIR)/libs/opus/lib",
|
"$(PROJECT_DIR)/libs/opus/lib",
|
||||||
"$(PROJECT_DIR)/libs/openssl/lib",
|
"$(PROJECT_DIR)/libs/openssl/lib",
|
||||||
);
|
);
|
||||||
|
PRODUCT_BUNDLE_IDENTIFIER = "com.moonlight-stream.$(PRODUCT_NAME:rfc1034identifier)";
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
PROVISIONING_PROFILE = "";
|
PROVISIONING_PROFILE = "";
|
||||||
SKIP_INSTALL = NO;
|
SKIP_INSTALL = NO;
|
||||||
@@ -1098,46 +1036,6 @@
|
|||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
FB290D2419B2C406004C83CF /* Debug */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Moonlight.app/Moonlight";
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
|
||||||
"$(inherited)",
|
|
||||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
|
||||||
);
|
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
|
||||||
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
|
||||||
GCC_PREPROCESSOR_DEFINITIONS = (
|
|
||||||
"DEBUG=1",
|
|
||||||
"$(inherited)",
|
|
||||||
);
|
|
||||||
INFOPLIST_FILE = "LimelightTests/LimelightTests-Info.plist";
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
|
||||||
WRAPPER_EXTENSION = xctest;
|
|
||||||
};
|
|
||||||
name = Debug;
|
|
||||||
};
|
|
||||||
FB290D2519B2C406004C83CF /* Release */ = {
|
|
||||||
isa = XCBuildConfiguration;
|
|
||||||
buildSettings = {
|
|
||||||
BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/Moonlight.app/Moonlight";
|
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
|
||||||
"$(SDKROOT)/Developer/Library/Frameworks",
|
|
||||||
"$(inherited)",
|
|
||||||
"$(DEVELOPER_FRAMEWORKS_DIR)",
|
|
||||||
);
|
|
||||||
GCC_PRECOMPILE_PREFIX_HEADER = YES;
|
|
||||||
GCC_PREFIX_HEADER = "Limelight/Limelight-Prefix.pch";
|
|
||||||
INFOPLIST_FILE = "LimelightTests/LimelightTests-Info.plist";
|
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
|
||||||
TEST_HOST = "$(BUNDLE_LOADER)";
|
|
||||||
WRAPPER_EXTENSION = xctest;
|
|
||||||
};
|
|
||||||
name = Release;
|
|
||||||
};
|
|
||||||
/* End XCBuildConfiguration section */
|
/* End XCBuildConfiguration section */
|
||||||
|
|
||||||
/* Begin XCConfigurationList section */
|
/* Begin XCConfigurationList section */
|
||||||
@@ -1159,26 +1057,19 @@
|
|||||||
defaultConfigurationIsVisible = 0;
|
defaultConfigurationIsVisible = 0;
|
||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
FB290D2319B2C406004C83CF /* Build configuration list for PBXNativeTarget "LimelightTests" */ = {
|
|
||||||
isa = XCConfigurationList;
|
|
||||||
buildConfigurations = (
|
|
||||||
FB290D2419B2C406004C83CF /* Debug */,
|
|
||||||
FB290D2519B2C406004C83CF /* Release */,
|
|
||||||
);
|
|
||||||
defaultConfigurationIsVisible = 0;
|
|
||||||
defaultConfigurationName = Release;
|
|
||||||
};
|
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
/* Begin XCVersionGroup section */
|
/* Begin XCVersionGroup section */
|
||||||
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
|
FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */ = {
|
||||||
isa = XCVersionGroup;
|
isa = XCVersionGroup;
|
||||||
children = (
|
children = (
|
||||||
|
FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */,
|
||||||
|
FBB460391B50ACE400F3099C /* Moonlight v1.0.xcdatamodel */,
|
||||||
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */,
|
FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */,
|
||||||
FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */,
|
FB4678F21A51BDCB00377732 /* Limelight 0.3.0.xcdatamodel */,
|
||||||
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */,
|
FB290D0619B2C406004C83CF /* Limelight.xcdatamodel */,
|
||||||
);
|
);
|
||||||
currentVersion = FB6549621A60B4A9001C8F39 /* Limelight 0.3.1.xcdatamodel */;
|
currentVersion = FB53E1441BE5DCBC00CD6ECE /* Moonlight v1.0-2.xcdatamodel */;
|
||||||
path = Limelight.xcdatamodeld;
|
path = Limelight.xcdatamodeld;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
versionGroupType = wrapper.xcdatamodel;
|
versionGroupType = wrapper.xcdatamodel;
|
||||||
|
|||||||
@@ -1,12 +1,8 @@
|
|||||||
#Moonlight iOS
|
#Moonlight iOS
|
||||||
|
|
||||||
|
#### Now available on the [App Store](https://itunes.apple.com/us/app/moonlight-game-streaming/id1000551566?mt=8)
|
||||||
|
|
||||||
[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
|
[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.
|
your powerful desktop computer to your iOS Device.
|
||||||
|
|
||||||
This is actively being developed and will be available on the App Store soon - check back here or on [our website](http://moonlight-stream.com) for updates.
|
There are also versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [PC](https://github.com/moonlight-stream/moonlight-pc).
|
||||||
|
|
||||||
We understand that Moonlight users are eager for the opportunity to stream their Steam collection to their iOS devices. Moonlight for iOS is in the testing stage and preliminary versions are available for beta testers.
|
|
||||||
|
|
||||||
In the meantime, check out the existing versions for [Android](https://github.com/moonlight-stream/moonlight-android) and [PC](https://github.com/moonlight-stream/moonlight-pc). Also, a client for [Windows and Windows Phone](https://github.com/moonlight-stream/moonlight-windows) is in the works and actively being developed.
|
|
||||||
|
|
||||||
Please be patient as we work to bring Moonlight to more platforms.
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<customFonts key="customFonts">
|
<customFonts key="customFonts">
|
||||||
<mutableArray key="Roboto-Regular.ttf">
|
<mutableArray key="Roboto-Regular.ttf">
|
||||||
@@ -13,9 +14,11 @@
|
|||||||
<scene sceneID="Me4-Nr-liz">
|
<scene sceneID="Me4-Nr-liz">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
|
<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"/>
|
<rect key="frame" x="0.0" y="64" width="1024" height="704"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<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"/>
|
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
|
||||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
|
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
|
||||||
<size key="itemSize" width="150" height="200"/>
|
<size key="itemSize" width="150" height="200"/>
|
||||||
@@ -24,14 +27,16 @@
|
|||||||
<inset key="sectionInset" minX="20" minY="20" maxX="20" maxY="20"/>
|
<inset key="sectionInset" minX="20" minY="20" maxX="20" maxY="20"/>
|
||||||
</collectionViewFlowLayout>
|
</collectionViewFlowLayout>
|
||||||
<cells>
|
<cells>
|
||||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="fv6-NS-qsK">
|
<collectionViewCell 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"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="150" height="200"/>
|
<rect key="frame" x="0.0" y="0.0" width="150" height="200"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
|
<animations/>
|
||||||
</collectionViewCell>
|
</collectionViewCell>
|
||||||
</cells>
|
</cells>
|
||||||
<connections>
|
<connections>
|
||||||
@@ -42,14 +47,15 @@
|
|||||||
<navigationItem key="navigationItem" id="pSu-bl-gL9">
|
<navigationItem key="navigationItem" id="pSu-bl-gL9">
|
||||||
<barButtonItem key="leftBarButtonItem" style="done" id="mSL-ru-nRm">
|
<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">
|
<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"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
|
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
|
||||||
<state key="normal" title="Moonlight" image="Logo">
|
<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"/>
|
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</state>
|
</state>
|
||||||
</button>
|
</button>
|
||||||
|
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</barButtonItem>
|
</barButtonItem>
|
||||||
<barButtonItem key="rightBarButtonItem" title="No Host Selected" id="KDy-JC-2sU">
|
<barButtonItem key="rightBarButtonItem" title="No Host Selected" id="KDy-JC-2sU">
|
||||||
<color key="tintColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="16" y="39" width="151" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="14" y="68" width="213" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<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"/>
|
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</slider>
|
</slider>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Framerate" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Aiv-r8-9k2">
|
<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"/>
|
<rect key="frame" x="16" y="106" width="79" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="16" y="171" width="82" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="16" y="200" width="209" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="720p"/>
|
<segment title="720p"/>
|
||||||
<segment title="1080p"/>
|
<segment title="1080p"/>
|
||||||
<segment title="Native"/>
|
|
||||||
</segments>
|
</segments>
|
||||||
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</segmentedControl>
|
</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">
|
<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"/>
|
<rect key="frame" x="16" y="236" width="153" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="tintColor" red="0.81533776120000001" green="0.85979419950000002" blue="0.91372549020000005" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="16" y="265" width="209" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="Off"/>
|
<segment title="Off"/>
|
||||||
<segment title="Auto"/>
|
<segment title="Auto"/>
|
||||||
@@ -135,6 +147,7 @@
|
|||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="lGK-vl-pdw">
|
<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"/>
|
<rect key="frame" x="16" y="135" width="209" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="30 Hz"/>
|
<segment title="30 Hz"/>
|
||||||
<segment title="60 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"/>
|
<color key="tintColor" red="0.72941176470000002" green="0.69411764710000001" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</segmentedControl>
|
</segmentedControl>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
|
<color key="backgroundColor" cocoaTouchSystemColor="viewFlipsideBackgroundColor"/>
|
||||||
</view>
|
</view>
|
||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
@@ -164,6 +178,7 @@
|
|||||||
<view key="view" contentMode="scaleToFill" id="hGs-BR-t4b">
|
<view key="view" contentMode="scaleToFill" id="hGs-BR-t4b">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
<rect key="frame" x="0.0" y="0.0" width="1024" height="768"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
@@ -184,6 +199,8 @@
|
|||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" translucent="NO" id="RUe-14-4Ya">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="768" height="44"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<animations/>
|
||||||
|
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</navigationBar>
|
</navigationBar>
|
||||||
<connections>
|
<connections>
|
||||||
<segue destination="wb7-af-jn8" kind="relationship" relationship="rootViewController" id="nkY-JG-Wki"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="502" y="374" width="20" height="20"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
</activityIndicatorView>
|
</activityIndicatorView>
|
||||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dDs-kT-po6">
|
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="dDs-kT-po6">
|
||||||
<rect key="frame" x="491" y="402" width="42" height="21"/>
|
<rect key="frame" x="491" y="402" width="42" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
</label>
|
</label>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
<animations/>
|
||||||
|
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
<navigationItem key="navigationItem" id="iUf-9X-GeA"/>
|
<navigationItem key="navigationItem" id="iUf-9X-GeA"/>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
@@ -241,8 +261,10 @@
|
|||||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" id="N0D-dj-EuF">
|
<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"/>
|
<rect key="frame" x="494" y="365" width="37" height="37"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
</activityIndicatorView>
|
</activityIndicatorView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
<?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>
|
<dependencies>
|
||||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="7703"/>
|
<deployment identifier="iOS"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="8154"/>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<customFonts key="customFonts">
|
<customFonts key="customFonts">
|
||||||
<mutableArray key="Roboto-Regular.ttf">
|
<mutableArray key="Roboto-Regular.ttf">
|
||||||
@@ -13,9 +14,11 @@
|
|||||||
<scene sceneID="emz-kO-L7q">
|
<scene sceneID="emz-kO-L7q">
|
||||||
<objects>
|
<objects>
|
||||||
<viewController id="dgh-JZ-Q7z" customClass="MainFrameViewController" sceneMemberID="viewController">
|
<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"/>
|
<rect key="frame" x="0.0" y="64" width="568" height="256"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<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"/>
|
<inset key="contentInset" minX="40" minY="20" maxX="40" maxY="20"/>
|
||||||
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="YcZ-cR-3tK">
|
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="YcZ-cR-3tK">
|
||||||
<size key="itemSize" width="90" height="120"/>
|
<size key="itemSize" width="90" height="120"/>
|
||||||
@@ -24,14 +27,16 @@
|
|||||||
<inset key="sectionInset" minX="20" minY="20" maxX="20" maxY="20"/>
|
<inset key="sectionInset" minX="20" minY="20" maxX="20" maxY="20"/>
|
||||||
</collectionViewFlowLayout>
|
</collectionViewFlowLayout>
|
||||||
<cells>
|
<cells>
|
||||||
<collectionViewCell opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" reuseIdentifier="AppCell" id="Uqv-Di-fzX">
|
<collectionViewCell 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"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
<view key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="90" height="120"/>
|
<rect key="frame" x="0.0" y="0.0" width="90" height="120"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
|
<animations/>
|
||||||
</collectionViewCell>
|
</collectionViewCell>
|
||||||
</cells>
|
</cells>
|
||||||
<connections>
|
<connections>
|
||||||
@@ -43,8 +48,9 @@
|
|||||||
<navigationItem key="navigationItem" id="1jn-Sf-Xky">
|
<navigationItem key="navigationItem" id="1jn-Sf-Xky">
|
||||||
<barButtonItem key="leftBarButtonItem" style="done" id="zAn-CM-7Yz">
|
<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">
|
<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"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
|
<fontDescription key="fontDescription" name="Roboto-Regular" family="Roboto" pointSize="16"/>
|
||||||
<state key="normal" title="Moonlight" image="Logo">
|
<state key="normal" title="Moonlight" image="Logo">
|
||||||
<color key="titleColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<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">
|
<view key="view" contentMode="scaleToFill" id="Usg-e0-g4a">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
<rect key="frame" x="0.0" y="0.0" width="568" height="320"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="1" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="14" y="49" width="204" height="31"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<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"/>
|
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</slider>
|
</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">
|
<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"/>
|
<rect key="frame" x="16" y="20" width="151" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -109,6 +118,7 @@
|
|||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="dLF-qJ-2nY">
|
<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"/>
|
<rect key="frame" x="16" y="116" width="200" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="30 Hz"/>
|
<segment title="30 Hz"/>
|
||||||
<segment title="60 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">
|
<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"/>
|
<rect key="frame" x="16" y="87" width="79" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="16" y="152" width="82" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -132,16 +144,17 @@
|
|||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" id="PCM-t4-Sha">
|
<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"/>
|
<rect key="frame" x="16" y="181" width="200" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="720p"/>
|
<segment title="720p"/>
|
||||||
<segment title="1080p"/>
|
<segment title="1080p"/>
|
||||||
<segment title="Native"/>
|
|
||||||
</segments>
|
</segments>
|
||||||
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</segmentedControl>
|
</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">
|
<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"/>
|
<rect key="frame" x="16" y="217" width="153" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="textColor" red="0.96078431372549022" green="0.98039215686274506" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<nil key="highlightedColor"/>
|
||||||
@@ -149,6 +162,7 @@
|
|||||||
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="1" id="WGf-9d-eAm">
|
<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"/>
|
<rect key="frame" x="16" y="246" width="200" height="29"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment title="Off"/>
|
<segment title="Off"/>
|
||||||
<segment title="Auto"/>
|
<segment title="Auto"/>
|
||||||
@@ -158,6 +172,7 @@
|
|||||||
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
<color key="tintColor" red="0.72941176470588232" green="0.69411764705882351" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
||||||
</segmentedControl>
|
</segmentedControl>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" red="0.12156862745098039" green="0.12941176470588237" blue="0.14117647058823529" alpha="1" colorSpace="calibratedRGB"/>
|
<color key="backgroundColor" red="0.12156862745098039" green="0.12941176470588237" blue="0.14117647058823529" alpha="1" colorSpace="calibratedRGB"/>
|
||||||
</view>
|
</view>
|
||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
@@ -181,6 +196,8 @@
|
|||||||
<navigationBar key="navigationBar" contentMode="scaleToFill" barStyle="black" translucent="NO" id="0ZA-Ec-QgD">
|
<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"/>
|
<rect key="frame" x="0.0" y="0.0" width="320" height="44"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<animations/>
|
||||||
|
<color key="barTintColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
<textAttributes key="titleTextAttributes">
|
<textAttributes key="titleTextAttributes">
|
||||||
<offsetWrapper key="textShadowOffset" horizontal="0.0" vertical="0.0"/>
|
<offsetWrapper key="textShadowOffset" horizontal="0.0" vertical="0.0"/>
|
||||||
</textAttributes>
|
</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">
|
<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"/>
|
<rect key="frame" x="262" y="149" width="45" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
<fontDescription key="fontDescription" type="system" pointSize="17"/>
|
||||||
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
<color key="textColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="calibratedRGB"/>
|
||||||
<nil key="highlightedColor"/>
|
<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">
|
<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"/>
|
<rect key="frame" x="274" y="121" width="20" height="20"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
||||||
|
<animations/>
|
||||||
</activityIndicatorView>
|
</activityIndicatorView>
|
||||||
</subviews>
|
</subviews>
|
||||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
|
<animations/>
|
||||||
|
<color key="backgroundColor" white="0.33333333333333331" alpha="1" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
<navigationItem key="navigationItem" id="8uX-4T-BiC"/>
|
<navigationItem key="navigationItem" id="8uX-4T-BiC"/>
|
||||||
<nil key="simulatedStatusBarMetrics"/>
|
<nil key="simulatedStatusBarMetrics"/>
|
||||||
@@ -239,8 +259,10 @@
|
|||||||
<subviews>
|
<subviews>
|
||||||
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="oNu-Gu-QeM">
|
<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"/>
|
<rect key="frame" x="266" y="141" width="37" height="37"/>
|
||||||
|
<animations/>
|
||||||
</activityIndicatorView>
|
</activityIndicatorView>
|
||||||
</subviews>
|
</subviews>
|
||||||
|
<animations/>
|
||||||
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
|
<color key="backgroundColor" white="0.0" alpha="0.5" colorSpace="calibratedWhite"/>
|
||||||
</view>
|
</view>
|
||||||
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
<simulatedOrientationMetrics key="simulatedOrientationMetrics" orientation="landscapeRight"/>
|
||||||
@@ -256,9 +278,4 @@
|
|||||||
<resources>
|
<resources>
|
||||||
<image name="Logo" width="32" height="32"/>
|
<image name="Logo" width="32" height="32"/>
|
||||||
</resources>
|
</resources>
|
||||||
<simulatedMetricsContainer key="defaultSimulatedMetrics">
|
|
||||||
<simulatedStatusBarMetrics key="statusBar"/>
|
|
||||||
<simulatedOrientationMetrics key="orientation"/>
|
|
||||||
<simulatedScreenMetrics key="destination" type="retina4"/>
|
|
||||||
</simulatedMetricsContainer>
|
|
||||||
</document>
|
</document>
|
||||||
@@ -616,7 +616,10 @@ OPUS_EXPORT void opus_pcm_soft_clip(float *pcm, int frame_size, int channels, fl
|
|||||||
* merged. Splitting valid Opus packets is always guaranteed to succeed,
|
* merged. Splitting valid Opus packets is always guaranteed to succeed,
|
||||||
* whereas merging valid packets only succeeds if all frames have the same
|
* whereas merging valid packets only succeeds if all frames have the same
|
||||||
* mode, bandwidth, and frame size, and when the total duration of the merged
|
* mode, bandwidth, and frame size, and when the total duration of the merged
|
||||||
* packet is no more than 120 ms.
|
* packet is no more than 120 ms. The 120 ms limit comes from the
|
||||||
|
* specification and limits decoder memory requirements at a point where
|
||||||
|
* framing overhead becomes negligible.
|
||||||
|
*
|
||||||
* The repacketizer currently only operates on elementary Opus
|
* The repacketizer currently only operates on elementary Opus
|
||||||
* streams. It will not manipualte multistream packets successfully, except in
|
* streams. It will not manipualte multistream packets successfully, except in
|
||||||
* the degenerate case where they consist of data from a single stream.
|
* the degenerate case where they consist of data from a single stream.
|
||||||
|
|||||||
@@ -713,6 +713,10 @@ extern "C" {
|
|||||||
OPUS_EXPORT const char *opus_strerror(int error);
|
OPUS_EXPORT const char *opus_strerror(int error);
|
||||||
|
|
||||||
/** Gets the libopus version string.
|
/** Gets the libopus version string.
|
||||||
|
*
|
||||||
|
* Applications may look for the substring "-fixed" in the version string to
|
||||||
|
* determine whether they have a fixed-point or floating-point build at
|
||||||
|
* runtime.
|
||||||
*
|
*
|
||||||
* @returns Version string
|
* @returns Version string
|
||||||
*/
|
*/
|
||||||
|
|||||||