mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2025-07-03 16:26:07 +00:00
328 lines
13 KiB
Objective-C
328 lines
13 KiB
Objective-C
// MainFrameViewController.m
|
|
// Limelight-iOS
|
|
//
|
|
// Created by Diego Waxemberg on 1/17/14.
|
|
// Copyright (c) 2014 Diego Waxemberg. All rights reserved.
|
|
//
|
|
|
|
#import "MainFrameViewController.h"
|
|
#import "Computer.h"
|
|
#import "CryptoManager.h"
|
|
#import "HttpManager.h"
|
|
#import "Connection.h"
|
|
#import "VideoDecoderRenderer.h"
|
|
#import "StreamManager.h"
|
|
#import "Utils.h"
|
|
#import "UIComputerView.h"
|
|
#import "UIAppView.h"
|
|
#import "App.h"
|
|
#import "SettingsViewController.h"
|
|
#import "DataManager.h"
|
|
#import "Settings.h"
|
|
|
|
@implementation MainFrameViewController {
|
|
NSOperationQueue* _opQueue;
|
|
MDNSManager* _mDNSManager;
|
|
Computer* _selectedHost;
|
|
NSString* _uniqueId;
|
|
NSData* _cert;
|
|
|
|
UIAlertView* _pairAlert;
|
|
UIScrollView* hostScrollView;
|
|
}
|
|
static NSString* deviceName = @"roth";
|
|
static NSMutableSet* hostList;
|
|
static NSArray* appList;
|
|
static StreamConfiguration* streamConfig;
|
|
|
|
+ (StreamConfiguration*) getStreamConfiguration {
|
|
return streamConfig;
|
|
}
|
|
|
|
- (void)showPIN:(NSString *)PIN {
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing" message:[NSString stringWithFormat:@"Enter the following PIN on the host machine: %@", PIN]delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
|
[_pairAlert show];
|
|
});
|
|
}
|
|
|
|
- (void)pairFailed:(NSString *)message {
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
[_pairAlert dismissWithClickedButtonIndex:0 animated:NO];
|
|
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Failed" message:message delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
|
[_pairAlert show];
|
|
});
|
|
}
|
|
|
|
- (void)pairSuccessful {
|
|
dispatch_sync(dispatch_get_main_queue(), ^{
|
|
[_pairAlert dismissWithClickedButtonIndex:0 animated:NO];
|
|
_pairAlert = [[UIAlertView alloc] initWithTitle:@"Pairing Succesful" message:@"Successfully paired to host" delegate:self cancelButtonTitle:@"Ok" otherButtonTitles:nil, nil];
|
|
[_pairAlert show];
|
|
});
|
|
}
|
|
|
|
- (void)alreadyPaired {
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
|
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:_selectedHost.hostName uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
|
NSData* appListResp = [hMan executeRequestSynchronously:[hMan newAppListRequest]];
|
|
appList = [HttpManager getAppListFromXML:appListResp];
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
[self updateApps];
|
|
_computerNameButton.title = _selectedHost.displayName;
|
|
});
|
|
[AppManager retrieveAppAssets:appList withManager:hMan andCallback:self];
|
|
});
|
|
}
|
|
|
|
- (void)showHostSelectionView {
|
|
appList = [[NSArray alloc] init];
|
|
_computerNameButton.title = @"";
|
|
[self.collectionView reloadData];
|
|
[self.view addSubview:hostScrollView];
|
|
}
|
|
|
|
- (void) receivedAssetForApp:(App*)app {
|
|
[self.collectionView reloadData];
|
|
}
|
|
|
|
- (void)displayDnsFailedDialog {
|
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"Network Error"
|
|
message:@"Failed to resolve host."
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
|
[self presentViewController:alert animated:YES completion:nil];
|
|
}
|
|
|
|
- (void) hostClicked:(Computer *)computer {
|
|
NSLog(@"Clicked host: %@", computer.displayName);
|
|
_selectedHost = computer;
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
|
HttpManager* hMan = [[HttpManager alloc] initWithHost:computer.hostName uniqueId:_uniqueId deviceName:deviceName cert:_cert];
|
|
NSData* serverInfoResp = [hMan executeRequestSynchronously:[hMan newServerInfoRequest]];
|
|
if ([[HttpManager getStringFromXML:serverInfoResp tag:@"PairStatus"] isEqualToString:@"1"]) {
|
|
NSLog(@"Already Paired");
|
|
[self alreadyPaired];
|
|
} else {
|
|
NSLog(@"Trying to pair");
|
|
PairManager* pMan = [[PairManager alloc] initWithManager:hMan andCert:_cert callback:self];
|
|
[_opQueue addOperation:pMan];
|
|
}
|
|
});
|
|
}
|
|
|
|
- (void) addHostClicked {
|
|
NSLog(@"Clicked add host");
|
|
UIAlertController* alertController = [UIAlertController alertControllerWithTitle:@"Host Address" message:@"Please enter a hostname or IP address" preferredStyle:UIAlertControllerStyleAlert];
|
|
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
|
[alertController addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
|
NSString* host = ((UITextField*)[[alertController textFields] objectAtIndex:0]).text;
|
|
Computer* newHost = [[Computer alloc] initWithIp:host];
|
|
[hostList addObject:newHost];
|
|
[self updateHosts:[hostList allObjects]];
|
|
DataManager* dataMan = [[DataManager alloc] init];
|
|
[dataMan createHost:newHost.displayName hostname:newHost.hostName];
|
|
[dataMan saveHosts];
|
|
|
|
//TODO: get pair state
|
|
|
|
|
|
}]];
|
|
[alertController addTextFieldWithConfigurationHandler:nil];
|
|
[self presentViewController:alertController animated:YES completion:nil];
|
|
}
|
|
|
|
- (void) appClicked:(App *)app {
|
|
NSLog(@"Clicked app: %@", app.appName);
|
|
streamConfig = [[StreamConfiguration alloc] init];
|
|
streamConfig.host = _selectedHost.hostName;
|
|
streamConfig.hostAddr = [Utils resolveHost:_selectedHost.hostName];
|
|
streamConfig.appID = app.appId;
|
|
if (streamConfig.hostAddr == 0) {
|
|
[self displayDnsFailedDialog];
|
|
return;
|
|
}
|
|
|
|
DataManager* dataMan = [[DataManager alloc] init];
|
|
Settings* streamSettings = [dataMan retrieveSettings];
|
|
|
|
streamConfig.frameRate = [streamSettings.framerate intValue];
|
|
streamConfig.bitRate = [streamSettings.bitrate intValue];
|
|
streamConfig.height = [streamSettings.height intValue];
|
|
streamConfig.width = [streamSettings.width intValue];
|
|
|
|
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
|
}
|
|
|
|
- (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position {
|
|
// If we moved back to the center position, we should save the settings
|
|
if (position == FrontViewPositionLeft) {
|
|
[(SettingsViewController*)[revealController rearViewController] saveSettings];
|
|
}
|
|
}
|
|
|
|
- (void)viewDidLoad
|
|
{
|
|
[super viewDidLoad];
|
|
|
|
// Set the side bar button action. When it's tapped, it'll show up the sidebar.
|
|
[_limelightLogoButton addTarget:self.revealViewController action:@selector(revealToggle:) forControlEvents:UIControlEventTouchDown];
|
|
|
|
// Set the host name button action. When it's tapped, it'll show up the host selection view.
|
|
[_computerNameButton setTarget:self];
|
|
[_computerNameButton setAction:@selector(showHostSelectionView)];
|
|
|
|
// Set the gesture
|
|
[self.view addGestureRecognizer:self.revealViewController.panGestureRecognizer];
|
|
|
|
[self.revealViewController setDelegate:self];
|
|
|
|
//NSArray* streamConfigVals = [[NSArray alloc] initWithObjects:@"1280x720 (30Hz)", @"1280x720 (60Hz)", @"1920x1080 (30Hz)", @"1920x1080 (60Hz)",nil];
|
|
|
|
_opQueue = [[NSOperationQueue alloc] init];
|
|
[CryptoManager generateKeyPairUsingSSl];
|
|
_uniqueId = [CryptoManager getUniqueID];
|
|
_cert = [CryptoManager readCertFromFile];
|
|
|
|
// Only initialize the host picker list once
|
|
if (hostList == nil) {
|
|
hostList = [[NSMutableSet alloc] init];
|
|
}
|
|
|
|
[self setAutomaticallyAdjustsScrollViewInsets:NO];
|
|
|
|
hostScrollView = [[UIScrollView alloc] init];
|
|
hostScrollView.frame = CGRectMake(0, 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];
|
|
|
|
[self retrieveSavedHosts];
|
|
[self updateHosts:[hostList allObjects]];
|
|
[self.view addSubview:hostScrollView];
|
|
}
|
|
|
|
- (void)viewDidAppear:(BOOL)animated
|
|
{
|
|
[super viewDidAppear:animated];
|
|
[self.navigationController setNavigationBarHidden:NO animated:YES];
|
|
|
|
// Hide 1px border line
|
|
UIImage* fakeImage = [[UIImage alloc] init];
|
|
[self.navigationController.navigationBar setShadowImage:fakeImage];
|
|
[self.navigationController.navigationBar setBackgroundImage:fakeImage forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault];
|
|
|
|
_mDNSManager = [[MDNSManager alloc] initWithCallback:self];
|
|
[_mDNSManager searchForHosts];
|
|
}
|
|
|
|
- (void)viewDidDisappear:(BOOL)animated
|
|
{
|
|
[super viewDidDisappear:animated];
|
|
[_mDNSManager stopSearching];
|
|
}
|
|
|
|
- (void) retrieveSavedHosts {
|
|
//TODO: Get rid of Computer and only use Host
|
|
|
|
DataManager* dataMan = [[DataManager alloc] init];
|
|
NSArray* hosts = [dataMan retrieveHosts];
|
|
for (Host* host in hosts) {
|
|
Computer* comp = [[Computer alloc] initWithIp:host.address];
|
|
comp.displayName = host.name;
|
|
[hostList addObject:comp];
|
|
}
|
|
}
|
|
|
|
- (void)updateHosts:(NSArray *)hosts {
|
|
[hostList addObjectsFromArray:hosts];
|
|
[[hostScrollView subviews] makeObjectsPerformSelector:@selector(removeFromSuperview)];
|
|
UIComputerView* addComp = [[UIComputerView alloc] initForAddWithCallback:self];
|
|
UIComputerView* compView;
|
|
float prevEdge = -1;
|
|
for (Computer* comp in hostList) {
|
|
compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self];
|
|
compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2);
|
|
prevEdge = compView.frame.origin.x + compView.frame.size.width;
|
|
[hostScrollView addSubview:compView];
|
|
}
|
|
|
|
prevEdge = [self getCompViewX:addComp addComp:addComp prevEdge:prevEdge];
|
|
addComp.center = CGPointMake(prevEdge, hostScrollView.frame.size.height / 2);
|
|
|
|
[hostScrollView addSubview:addComp];
|
|
[hostScrollView setContentSize:CGSizeMake(prevEdge + addComp.frame.size.width, hostScrollView.frame.size.height)];
|
|
}
|
|
|
|
- (float) getCompViewX:(UIComputerView*)comp addComp:(UIComputerView*)addComp prevEdge:(float)prevEdge {
|
|
if (prevEdge == -1) {
|
|
return hostScrollView.frame.origin.x + comp.frame.size.width / 2 + addComp.frame.size.width / 2;
|
|
} else {
|
|
return prevEdge + addComp.frame.size.width / 2 + comp.frame.size.width / 2;
|
|
}
|
|
}
|
|
|
|
- (void) updateApps {
|
|
[hostScrollView removeFromSuperview];
|
|
[self.collectionView reloadData];
|
|
}
|
|
|
|
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
|
|
UICollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"AppCell" forIndexPath:indexPath];
|
|
|
|
App* app = appList[indexPath.row];
|
|
UIAppView* appView = [[UIAppView alloc] initWithApp:app andCallback:self];
|
|
[appView updateAppImage];
|
|
|
|
if (appView.bounds.size.width > 10.0) {
|
|
CGFloat scale = cell.bounds.size.width / appView.bounds.size.width;
|
|
[appView setCenter:CGPointMake(appView.bounds.size.width / 2 * scale, appView.bounds.size.height / 2 * scale)];
|
|
appView.transform = CGAffineTransformMakeScale(scale, scale);
|
|
}
|
|
|
|
[cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added
|
|
[cell addSubview:appView];
|
|
|
|
return cell;
|
|
}
|
|
|
|
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
|
|
return 1; // App collection only
|
|
}
|
|
|
|
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
|
|
return appList.count;
|
|
}
|
|
|
|
- (BOOL)validatePcSelected {
|
|
if (_selectedHost == NULL) {
|
|
UIAlertController* alert = [UIAlertController alertControllerWithTitle:@"No PC Selected"
|
|
message:@"You must select a PC to continue."
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
[alert addAction:[UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDestructive handler:nil]];
|
|
[self presentViewController:alert animated:YES completion:nil];
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
- (void)didReceiveMemoryWarning
|
|
{
|
|
[super didReceiveMemoryWarning];
|
|
// Dispose of any resources that can be recreated.
|
|
}
|
|
|
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
|
|
[self.view endEditing:YES];
|
|
}
|
|
|
|
- (BOOL)textFieldShouldReturn:(UITextField *)textField {
|
|
[textField resignFirstResponder];
|
|
return YES;
|
|
}
|
|
|
|
- (BOOL)shouldAutorotate {
|
|
return YES;
|
|
}
|
|
@end
|