feat: disconnect & quit current app in tool box

This commit is contained in:
TrueZhuanjia committed 2025-08-18 23:28:19 +08:00
1 parent 85e6eb9eb6
commit 0c1fc66be8
5 files changed
+95 -28

No files matched your search

@@ -260,6 +260,29 @@
} }
} }
}, },
"[ Disconnect & quit app ]" : {
"extractionState" : "manual",
"localizations" : {
"zh-Hans" : {
"stringUnit" : {
"state" : "translated",
"value" : "[ 断开连接并退出应用 ]"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "[ 斷開連線並退出應用程式 ]"
}
},
"zh-HK" : {
"stringUnit" : {
"state" : "translated",
"value" : "[ 斷開連線並退出應用程式 ]"
}
}
}
},
"[ Enter picture-in-picture mode ]" : { "[ Enter picture-in-picture mode ]" : {
"extractionState" : "manual", "extractionState" : "manual",
"localizations" : { "localizations" : {
@@ -31,8 +31,9 @@
-(void)expandSettingsView; -(void)expandSettingsView;
- (void)closeSettingViewAnimated:(BOOL)anaimated; - (void)closeSettingViewAnimated:(BOOL)anaimated;
-(void)reloadStreamConfig; - (void)reloadStreamConfig;
-(bool)isIPhonePortrait; - (bool)isIPhonePortrait;
- (void)quitRunningApp;
#endif #endif
- (void)fillResolutionTable:(CGSize*)resolutionTable externalDisplayMode:(NSInteger)externalDisplayMode; - (void)fillResolutionTable:(CGSize*)resolutionTable externalDisplayMode:(NSInteger)externalDisplayMode;
@@ -74,6 +74,7 @@
StreamFrameViewController* streamFrameViewController; StreamFrameViewController* streamFrameViewController;
id navBarAppearanceStandard; id navBarAppearanceStandard;
bool _viewJustAppeared; bool _viewJustAppeared;
TemporaryApp * launchedApp;
NSTimer *_foregroundHostUpdateTimer; NSTimer *_foregroundHostUpdateTimer;
@@ -771,6 +772,7 @@ static NSMutableSet* hostList;
} }
- (void) prepareToStreamApp:(TemporaryApp *)app { - (void) prepareToStreamApp:(TemporaryApp *)app {
launchedApp = app;
[self updateResolutionAccordingly]; [self updateResolutionAccordingly];
self.revealViewController.isStreaming = true; // tell the revealViewController streaming is started. self.revealViewController.isStreaming = true; // tell the revealViewController streaming is started.
_streamConfig = [[StreamConfiguration alloc] init]; _streamConfig = [[StreamConfiguration alloc] init];
@@ -913,6 +915,55 @@ static NSMutableSet* hostList;
#endif #endif
} }
- (HttpResponse* )requestToQuitApp:(TemporaryApp* )app{
HttpManager* hMan = [[HttpManager alloc] initWithHost:app.host];
HttpResponse* quitResponse = [[HttpResponse alloc] init];
HttpRequest* quitRequest = [HttpRequest requestForResponse: quitResponse withUrlRequest:[hMan newQuitAppRequest]];
// Exempt this host from discovery while handling the quit operation
[self->_discMan pauseDiscoveryForHost:app.host];
[hMan executeRequestSynchronously:quitRequest];
if (quitResponse.statusCode == 200) {
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest:false]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
if (![serverInfoResp isStatusOk] || [[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_BUSY"]) {
// On newer GFE versions, the quit request succeeds even though the app doesn't
// really quit if another client tries to kill your app. We'll patch the response
// to look like the old error in that case, so the UI behaves.
quitResponse.statusCode = 599;
}
else if ([serverInfoResp isStatusOk]) {
// Update the host object with this info
[serverInfoResp populateHost:app.host];
}
}
[self->_discMan resumeDiscoveryForHost:app.host];
return quitResponse;
}
- (void)quitRunningApp{
[self showLoadingFrame: ^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
HttpResponse* quitResponse = [self requestToQuitApp:self->launchedApp];
// If it fails, display an error and stop the current operation
if (quitResponse.statusCode != 200) {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:[LocalizationHelper localizedStringForKey:@"Quitting App Failed"]
message:[LocalizationHelper localizedStringForKey:@"Failed to quit app. If this app was started by another device, you'll need to quit from that device."]
preferredStyle:UIAlertControllerStyleAlert];
[alert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Ok"] style:UIAlertActionStyleDefault handler:nil]];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateAppsForHost:self->launchedApp.host];
[self hideLoadingFrame: ^{
[[self activeViewController] presentViewController:alert animated:YES completion:nil];
}];
});
}
else dispatch_async(dispatch_get_main_queue(), ^{[self hideLoadingFrame:nil];});
});
}];
}
- (void)appLongClicked:(TemporaryApp *)app view:(UIView *)view { - (void)appLongClicked:(TemporaryApp *)app view:(UIView *)view {
Log(LOG_D, @"Long clicked app: %@", app.name); Log(LOG_D, @"Long clicked app: %@", app.name);
@@ -968,30 +1019,7 @@ static NSMutableSet* hostList;
Log(LOG_I, @"Quitting application: %@", currentApp.name); Log(LOG_I, @"Quitting application: %@", currentApp.name);
[self showLoadingFrame: ^{ [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:app.host]; HttpResponse* quitResponse = [self requestToQuitApp:app];
HttpResponse* quitResponse = [[HttpResponse alloc] init];
HttpRequest* quitRequest = [HttpRequest requestForResponse: quitResponse withUrlRequest:[hMan newQuitAppRequest]];
// Exempt this host from discovery while handling the quit operation
[self->_discMan pauseDiscoveryForHost:app.host];
[hMan executeRequestSynchronously:quitRequest];
if (quitResponse.statusCode == 200) {
ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init];
[hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest:false]
fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]];
if (![serverInfoResp isStatusOk] || [[serverInfoResp getStringTag:@"state"] hasSuffix:@"_SERVER_BUSY"]) {
// On newer GFE versions, the quit request succeeds even though the app doesn't
// really quit if another client tries to kill your app. We'll patch the response
// to look like the old error in that case, so the UI behaves.
quitResponse.statusCode = 599;
}
else if ([serverInfoResp isStatusOk]) {
// Update the host object with this info
[serverInfoResp populateHost:app.host];
}
}
[self->_discMan resumeDiscoveryForHost:app.host];
// If it fails, display an error and stop the current operation // If it fails, display an error and stop the current operation
if (quitResponse.statusCode != 200) { if (quitResponse.statusCode != 200) {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:[LocalizationHelper localizedStringForKey:@"Quitting App Failed"] UIAlertController* alert = [UIAlertController alertControllerWithTitle:[LocalizationHelper localizedStringForKey:@"Quitting App Failed"]
@@ -983,6 +983,17 @@
- (void)disconnectRemoteSession { - (void)disconnectRemoteSession {
Log(LOG_I, @"Settings view disconnect the session in stream view"); Log(LOG_I, @"Settings view disconnect the session in stream view");
[self returnToMainFrame]; [self returnToMainFrame];
}
- (void)disconnectAndQuitApp{
[self returnToMainFrame];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(1.5);
dispatch_async(dispatch_get_main_queue(), ^{
[self.mainFrameViewcontroller quitRunningApp];
});
});
} }
- (void) connectionStarted { - (void) connectionStarted {
@@ -13,6 +13,7 @@ import UIKit
@objc optional func switchWidgetProfile() @objc optional func switchWidgetProfile()
@objc optional func bringUpSoftKeyboard() @objc optional func bringUpSoftKeyboard()
@objc optional func enterPip() @objc optional func enterPip()
@objc optional func disconnectAndQuitApp()
} }
@@ -28,12 +29,13 @@ import UIKit
private let viewBackgroundColor = UIColor(white: 0.2, alpha: 0.8); private let viewBackgroundColor = UIColor(white: 0.2, alpha: 0.8);
private let highlightColor = UIColor(white: 0.55, alpha: 0.8); private let highlightColor = UIColor(white: 0.55, alpha: 0.8);
private let titleLabel = UILabel() private let titleLabel = UILabel()
@objc public var specialEntries : NSMutableArray = ["widgetSwitchTool", "widgetLayoutTool", "bringUpSoftKeyboard", "enterPip"] @objc public var specialEntries : NSMutableArray = ["widgetSwitchTool", "widgetLayoutTool", "bringUpSoftKeyboard", "enterPip", "disconnectAndQuitApp"]
private let specialEntryAliasDic : [String:String] = [ private let specialEntryAliasDic : [String:String] = [
"widgetSwitchTool":SwiftLocalizationHelper.localizedString(forKey: "[ Switch on-screen widget profile ]"), "widgetSwitchTool":SwiftLocalizationHelper.localizedString(forKey: "[ Switch on-screen widget profile ]"),
"widgetLayoutTool":SwiftLocalizationHelper.localizedString(forKey: "[ On-screen widget tool ]"), "widgetLayoutTool":SwiftLocalizationHelper.localizedString(forKey: "[ On-screen widget tool ]"),
"bringUpSoftKeyboard":SwiftLocalizationHelper.localizedString(forKey: "[ Bring up soft keyboard ]"), "bringUpSoftKeyboard":SwiftLocalizationHelper.localizedString(forKey: "[ Bring up soft keyboard ]"),
"enterPip":SwiftLocalizationHelper.localizedString(forKey: "[ Enter picture-in-picture mode ]") "enterPip":SwiftLocalizationHelper.localizedString(forKey: "[ Enter picture-in-picture mode ]"),
"disconnectAndQuitApp":SwiftLocalizationHelper.localizedString(forKey: "[ Disconnect & quit app ]")
] ]
private var viewPinned: Bool = false private var viewPinned: Bool = false
@@ -379,6 +381,8 @@ import UIKit
specialEntryDelegate?.bringUpSoftKeyboard?() specialEntryDelegate?.bringUpSoftKeyboard?()
case "enterPip": case "enterPip":
specialEntryDelegate?.enterPip?() specialEntryDelegate?.enterPip?()
case "disconnectAndQuitApp":
specialEntryDelegate?.disconnectAndQuitApp?()
default: break default: break
} }
} }