mirror of
https://github.com/moonlight-stream/moonlight-ios.git
synced 2026-04-13 11:26:05 +00:00
Add support for hiding apps
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
@property (nullable, nonatomic, retain) NSString *name;
|
||||
@property (nullable, nonatomic, retain) NSString *installPath;
|
||||
@property (nonatomic) BOOL hdrSupported;
|
||||
@property (nonatomic) BOOL hidden;
|
||||
@property (nullable, nonatomic, retain) TemporaryHost *host;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
self.id = app.id;
|
||||
self.name = app.name;
|
||||
self.hdrSupported = app.hdrSupported;
|
||||
self.hidden = app.hidden;
|
||||
self.host = tempHost;
|
||||
|
||||
return self;
|
||||
@@ -25,6 +26,7 @@
|
||||
parent.id = self.id;
|
||||
parent.name = self.name;
|
||||
parent.hdrSupported = self.hdrSupported;
|
||||
parent.hidden = self.hidden;
|
||||
parent.host = host;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="17192" systemVersion="19H2" minimumToolsVersion="Xcode 7.3" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="">
|
||||
<entity name="App" representedClassName="App" syncable="YES" codeGenerationType="class">
|
||||
<attribute name="hdrSupported" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="hidden" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||
<attribute name="id" attributeType="String" syncable="YES"/>
|
||||
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||
<relationship name="host" maxCount="1" deletionRule="Nullify" destinationEntity="Host" inverseName="appList" inverseEntity="Host" syncable="YES"/>
|
||||
@@ -36,7 +37,7 @@
|
||||
<attribute name="width" attributeType="Integer 32" defaultValueString="1280" usesScalarValueType="NO" syncable="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="App" positionX="0" positionY="54" width="128" height="105"/>
|
||||
<element name="App" positionX="0" positionY="54" width="128" height="118"/>
|
||||
<element name="Host" positionX="0" positionY="0" width="128" height="210"/>
|
||||
<element name="Settings" positionX="0" positionY="0" width="128" height="268"/>
|
||||
</elements>
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
@protocol AppCallback <NSObject>
|
||||
|
||||
- (void) appClicked:(TemporaryApp*) app;
|
||||
- (void) appLongClicked:(TemporaryApp*) app;
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
#import "UIAppView.h"
|
||||
#import "AppAssetManager.h"
|
||||
|
||||
static const float REFRESH_CYCLE = 2.0f;
|
||||
static const float REFRESH_CYCLE = 1.0f;
|
||||
|
||||
@implementation UIAppView {
|
||||
TemporaryApp* _app;
|
||||
@@ -40,10 +40,15 @@ static UIImage* noImage;
|
||||
self.frame = CGRectMake(0, 0, 150, 200);
|
||||
#endif
|
||||
|
||||
[self setAlpha:app.hidden ? 0.4 : 1.0];
|
||||
|
||||
_appImage = [[UIImageView alloc] initWithFrame:self.frame];
|
||||
[_appImage setImage:noImage];
|
||||
[self addSubview:_appImage];
|
||||
|
||||
UILongPressGestureRecognizer* longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(appLongClicked:)];
|
||||
[self addGestureRecognizer:longPressRecognizer];
|
||||
|
||||
if (@available(iOS 9.0, tvOS 9.0, *)) {
|
||||
[self addTarget:self action:@selector(appClicked) forControlEvents:UIControlEventPrimaryActionTriggered];
|
||||
}
|
||||
@@ -78,6 +83,12 @@ static UIImage* noImage;
|
||||
[_callback appClicked:_app];
|
||||
}
|
||||
|
||||
- (void) appLongClicked:(UILongPressGestureRecognizer*)gesture {
|
||||
if (gesture.state == UIGestureRecognizerStateBegan) {
|
||||
[_callback appLongClicked:_app];
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateAppImage {
|
||||
if (_appOverlay != nil) {
|
||||
[_appOverlay removeFromSuperview];
|
||||
@@ -185,6 +196,9 @@ static UIImage* noImage;
|
||||
[self updateAppImage];
|
||||
}
|
||||
|
||||
// Update opacity if neccessary
|
||||
[self setAlpha:_app.hidden ? 0.4 : 1.0];
|
||||
|
||||
// Stop updating when we detach from our parent view
|
||||
if (self.superview != nil) {
|
||||
[self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE];
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
@implementation MainFrameViewController {
|
||||
NSOperationQueue* _opQueue;
|
||||
TemporaryHost* _selectedHost;
|
||||
BOOL _showHiddenApps;
|
||||
NSString* _uniqueId;
|
||||
NSData* _clientCert;
|
||||
DiscoveryManager* _discMan;
|
||||
@@ -208,6 +209,24 @@ static NSMutableSet* hostList;
|
||||
});
|
||||
}
|
||||
|
||||
- (void) updateAppEntry:(TemporaryApp*)app forHost:(TemporaryHost*)host {
|
||||
DataManager* database = [[DataManager alloc] init];
|
||||
NSMutableSet* newHostAppList = [NSMutableSet setWithSet:host.appList];
|
||||
|
||||
for (TemporaryApp* savedApp in newHostAppList) {
|
||||
if ([app.id isEqualToString:savedApp.id]) {
|
||||
savedApp.name = app.name;
|
||||
savedApp.hdrSupported = app.hdrSupported;
|
||||
savedApp.hidden = app.hidden;
|
||||
|
||||
host.appList = newHostAppList;
|
||||
|
||||
[database updateAppsForExistingHost:host];
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void) updateApplist:(NSSet*) newList forHost:(TemporaryHost*)host {
|
||||
DataManager* database = [[DataManager alloc] init];
|
||||
NSMutableSet* newHostAppList = [NSMutableSet setWithSet:host.appList];
|
||||
@@ -218,6 +237,7 @@ static NSMutableSet* hostList;
|
||||
if ([app.id isEqualToString:savedApp.id]) {
|
||||
savedApp.name = app.name;
|
||||
savedApp.hdrSupported = app.hdrSupported;
|
||||
// Don't propagate hidden, because we want the local data to prevail
|
||||
appAlreadyInList = YES;
|
||||
break;
|
||||
}
|
||||
@@ -275,6 +295,7 @@ static NSMutableSet* hostList;
|
||||
#endif
|
||||
|
||||
[_appManager stopRetrieving];
|
||||
_showHiddenApps = NO;
|
||||
_selectedHost = nil;
|
||||
_sortedAppList = nil;
|
||||
|
||||
@@ -466,6 +487,12 @@ static NSMutableSet* hostList;
|
||||
[[self activeViewController] presentViewController:wolAlert animated:YES completion:nil];
|
||||
}]];
|
||||
}
|
||||
else if (host.pairState == PairStatePaired) {
|
||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Show Hidden Apps" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
self->_showHiddenApps = YES;
|
||||
[self hostClicked:host view:view];
|
||||
}]];
|
||||
}
|
||||
[longClickAlert addAction:[UIAlertAction actionWithTitle:@"Test Network" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) {
|
||||
[self showLoadingFrame:^{
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
@@ -642,8 +669,8 @@ static NSMutableSet* hostList;
|
||||
}
|
||||
}
|
||||
|
||||
- (void) appClicked:(TemporaryApp *)app {
|
||||
Log(LOG_D, @"Clicked app: %@", app.name);
|
||||
- (void) appLongClicked:(TemporaryApp*) app {
|
||||
Log(LOG_D, @"Long clicked app: %@", app.name);
|
||||
|
||||
[_appManager stopRetrieving];
|
||||
|
||||
@@ -655,18 +682,43 @@ static NSMutableSet* hostList;
|
||||
[[self revealViewController] revealToggleAnimated:NO];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
TemporaryApp* currentApp = [self findRunningApp:app.host];
|
||||
|
||||
NSString* message;
|
||||
|
||||
if (currentApp == nil || [app.id isEqualToString:currentApp.id]) {
|
||||
if (app.hidden) {
|
||||
message = @"Hidden";
|
||||
}
|
||||
else {
|
||||
message = @"";
|
||||
}
|
||||
}
|
||||
else {
|
||||
message = [NSString stringWithFormat:@"%@ is currently running", currentApp.name];
|
||||
}
|
||||
|
||||
UIAlertController* alertController = [UIAlertController
|
||||
alertControllerWithTitle: app.name
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
[alertController addAction:[UIAlertAction
|
||||
actionWithTitle:currentApp == nil ? @"Launch App" : ([app.id isEqualToString:currentApp.id] ? @"Resume App" : @"Resume Running App") style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
if (currentApp != nil) {
|
||||
Log(LOG_I, @"Resuming application: %@", currentApp.name);
|
||||
[self prepareToStreamApp:currentApp];
|
||||
}
|
||||
else {
|
||||
Log(LOG_I, @"Launching application: %@", app.name);
|
||||
[self prepareToStreamApp:app];
|
||||
}
|
||||
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||
}]];
|
||||
|
||||
if (currentApp != nil) {
|
||||
UIAlertController* alertController = [UIAlertController
|
||||
alertControllerWithTitle: app.name
|
||||
message: [app.id isEqualToString:currentApp.id] ? @"" : [NSString stringWithFormat:@"%@ is currently running", currentApp.name]preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction
|
||||
actionWithTitle:[app.id isEqualToString:currentApp.id] ? @"Resume App" : @"Resume Running App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){
|
||||
Log(LOG_I, @"Resuming application: %@", currentApp.name);
|
||||
[self prepareToStreamApp:currentApp];
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:
|
||||
[app.id isEqualToString:currentApp.id] ? @"Quit App" : @"Quit Running App and Start" style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action){
|
||||
Log(LOG_I, @"Quitting application: %@", currentApp.name);
|
||||
@@ -713,9 +765,6 @@ static NSMutableSet* hostList;
|
||||
else {
|
||||
app.host.currentGame = @"0";
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Refresh the UI
|
||||
[self updateAppsForHost:app.host];
|
||||
|
||||
// If it succeeds and we're to start streaming, segue to the stream
|
||||
if (![app.id isEqualToString:currentApp.id]) {
|
||||
[self prepareToStreamApp:app];
|
||||
@@ -733,8 +782,39 @@ static NSMutableSet* hostList;
|
||||
}];
|
||||
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[[self activeViewController] presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
if (currentApp == nil || ![app.id isEqualToString:currentApp.id] || app.hidden) {
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:app.hidden ? @"Show App" : @"Hide App" style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) {
|
||||
app.hidden = !app.hidden;
|
||||
[self updateAppEntry:app forHost:app.host];
|
||||
|
||||
// Don't call updateAppsForHost because that will nuke this
|
||||
// app immediately if we're not showing hidden apps.
|
||||
}]];
|
||||
}
|
||||
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:nil]];
|
||||
[[self activeViewController] presentViewController:alertController animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (void) appClicked:(TemporaryApp *)app {
|
||||
Log(LOG_D, @"Clicked app: %@", app.name);
|
||||
|
||||
[_appManager stopRetrieving];
|
||||
|
||||
#if !TARGET_OS_TV
|
||||
if (currentPosition != FrontViewPositionLeft) {
|
||||
// This must not be animated because we need the position
|
||||
// to change (and notify our callback to save settings data)
|
||||
// before we call prepareToStreamApp.
|
||||
[[self revealViewController] revealToggleAnimated:NO];
|
||||
}
|
||||
#endif
|
||||
|
||||
if ([self findRunningApp:app.host]) {
|
||||
// If there's a running app, display a menu
|
||||
[self appLongClicked:app];
|
||||
} else {
|
||||
[self prepareToStreamApp:app];
|
||||
[self performSegueWithIdentifier:@"createStreamFrame" sender:nil];
|
||||
@@ -1188,6 +1268,16 @@ static NSMutableSet* hostList;
|
||||
_sortedAppList = [host.appList allObjects];
|
||||
_sortedAppList = [_sortedAppList sortedArrayUsingSelector:@selector(compareName:)];
|
||||
|
||||
if (!_showHiddenApps) {
|
||||
NSMutableArray* visibleAppList = [NSMutableArray array];
|
||||
for (TemporaryApp* app in _sortedAppList) {
|
||||
if (!app.hidden) {
|
||||
[visibleAppList addObject:app];
|
||||
}
|
||||
}
|
||||
_sortedAppList = visibleAppList;
|
||||
}
|
||||
|
||||
[hostScrollView removeFromSuperview];
|
||||
[self.collectionView reloadData];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user