diff --git a/VoidLink.xcodeproj/project.pbxproj b/VoidLink.xcodeproj/project.pbxproj index 752c74ae..7a6fc71a 100644 --- a/VoidLink.xcodeproj/project.pbxproj +++ b/VoidLink.xcodeproj/project.pbxproj @@ -78,7 +78,6 @@ DC1F5A07206436B20037755F /* ConnectionHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = DC1F5A06206436B20037755F /* ConnectionHelper.m */; }; F74BEF9C2C1A705600224667 /* OpenSSL in Frameworks */ = {isa = PBXBuildFile; productRef = F74BEF9B2C1A705600224667 /* OpenSSL */; }; FB1A674D2131E65900507771 /* KeyboardSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1A674C2131E65900507771 /* KeyboardSupport.m */; }; - FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */; }; FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */; }; FB290CF219B2C406004C83CF /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF119B2C406004C83CF /* Foundation.framework */; }; FB290CF419B2C406004C83CF /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FB290CF319B2C406004C83CF /* CoreGraphics.framework */; }; @@ -123,7 +122,6 @@ FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3494F19FF2174002D2A60 /* SettingsViewController.m */; }; FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */; }; FBD349621A0089F6002D2A60 /* DataManager.m in Sources */ = {isa = PBXBuildFile; fileRef = FBD349611A0089F6002D2A60 /* DataManager.m */; }; - FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86DF19F7A837001C18A8 /* UIComputerView.m */; }; FBDE86E619F82297001C18A8 /* UIAppView.m in Sources */ = {isa = PBXBuildFile; fileRef = FBDE86E519F82297001C18A8 /* UIAppView.m */; }; /* End PBXBuildFile section */ @@ -290,8 +288,6 @@ FB1A67642132419A00507771 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; FB1A67E421324A1F00507771 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS11.4.sdk/System/Library/Frameworks/CoreData.framework; sourceTree = DEVELOPER_DIR; }; FB1A67E921324DF300507771 /* libxml2.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libxml2.tbd; path = Platforms/AppleTVOS.platform/Developer/SDKs/AppleTVOS11.4.sdk/usr/lib/libxml2.tbd; sourceTree = DEVELOPER_DIR; }; - FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ComputerScrollView.h; sourceTree = ""; }; - FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ComputerScrollView.m; sourceTree = ""; }; FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppCollectionView.h; sourceTree = ""; }; FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppCollectionView.m; sourceTree = ""; }; FB290CEE19B2C406004C83CF /* VoidLink.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = VoidLink.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -376,8 +372,6 @@ FBD3495219FF36FB002D2A60 /* SWRevealViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SWRevealViewController.m; sourceTree = ""; }; FBD349601A0089F6002D2A60 /* DataManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = DataManager.h; path = Database/DataManager.h; sourceTree = ""; }; FBD349611A0089F6002D2A60 /* DataManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = DataManager.m; path = Database/DataManager.m; sourceTree = ""; }; - FBDE86DE19F7A837001C18A8 /* UIComputerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIComputerView.h; sourceTree = ""; }; - FBDE86DF19F7A837001C18A8 /* UIComputerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIComputerView.m; sourceTree = ""; }; FBDE86E419F82297001C18A8 /* UIAppView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UIAppView.h; sourceTree = ""; }; FBDE86E519F82297001C18A8 /* UIAppView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UIAppView.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -619,8 +613,6 @@ 841BAC912DE35D6B00DA639E /* ThemeManager.m */, 847D2FD82DDA00C800937A62 /* MenuSectionView.h */, 847D2FDA2DDA015F00937A62 /* MenuSectionView.m */, - FBDE86DE19F7A837001C18A8 /* UIComputerView.h */, - FBDE86DF19F7A837001C18A8 /* UIComputerView.m */, FBDE86E419F82297001C18A8 /* UIAppView.h */, FBDE86E519F82297001C18A8 /* UIAppView.m */, 1888C1902E24C2C800108730 /* AboutView.swift */, @@ -628,8 +620,6 @@ FB89463719F6473800339C8A /* Launch Screen.xib */, FB290D0819B2C406004C83CF /* Images.xcassets */, FB290D0519B2C406004C83CF /* Limelight.xcdatamodeld */, - FB1D59951BBCCB6400F482CA /* ComputerScrollView.h */, - FB1D59961BBCCB6400F482CA /* ComputerScrollView.m */, FB1D59981BBCCD7E00F482CA /* AppCollectionView.h */, FB1D59991BBCCD7E00F482CA /* AppCollectionView.m */, 843E93BD2C41528700B1651F /* OrientationHelper.swift */, @@ -1019,7 +1009,6 @@ 84351B112C29ACCB00A77989 /* OSCProfilesManager.m in Sources */, FB89462919F646E200339C8A /* mkcert.c in Sources */, FB9AFD281A7C84ED00872C98 /* HttpResponse.m in Sources */, - FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */, FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */, FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */, 84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */, @@ -1027,7 +1016,6 @@ 9777AAF32E2CF7A400D7FBAF /* Shaders-Linear.metal in Sources */, 84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */, 97E20DEA2E216532000D5DCA /* SceneDelegate.m in Sources */, - FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */, FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */, 843CC7F02C1E757D00BBC475 /* NativeTouchPointer.m in Sources */, FB89462C19F646E200339C8A /* HttpManager.m in Sources */, @@ -1292,7 +1280,7 @@ "$(PROJECT_DIR)/libs/SDL2/lib/iOS-Sim", "$(PROJECT_DIR)/libs/FFmpeg/lib/iOS-Sim", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 0.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.voidlink.tf.debug10.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; @@ -1357,7 +1345,7 @@ "$(PROJECT_DIR)/libs/SDL2/lib/iOS-Sim", "$(PROJECT_DIR)/libs/FFmpeg/lib/iOS-Sim", ); - MARKETING_VERSION = 1.0.0; + MARKETING_VERSION = 0.0.1; PRODUCT_BUNDLE_IDENTIFIER = com.voidlink.tf.iOS; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = ""; diff --git a/VoidLink/AboutView.swift b/VoidLink/AboutView.swift index d1d2d443..116b1ff8 100644 --- a/VoidLink/AboutView.swift +++ b/VoidLink/AboutView.swift @@ -10,8 +10,10 @@ import SwiftUI @available(iOS 13.0, *) + public struct AboutView: View { @Environment(\.presentationMode) var presentationMode + public var aboutVC:UIViewController public var body: some View { VStack(spacing: 10) { @@ -56,19 +58,18 @@ public struct AboutView: View { } } // 链接按钮 - if #available(iOS 14.0, *) { + if #available(iOS 14.0, *) { Link(SwiftLocalizationHelper.localizedString(forKey: "Join us"), destination: URL(string: SwiftLocalizationHelper.localizedString(forKey: "supportLink"))!) .padding(.top, 10) Spacer() // OK 按钮 - Button("OK") { - presentationMode.wrappedValue.dismiss() + Button(SwiftLocalizationHelper.localizedString(forKey: "OK")) { + aboutVC.dismiss(animated:true) } .padding() .background(Color.blue) .foregroundColor(.white) .frame(height: 46) - //.frame(width: 100) .cornerRadius(12) } else { HStack(spacing: 20) { @@ -84,8 +85,8 @@ public struct AboutView: View { .cornerRadius(12) .frame(height: 33) .frame(minWidth: 100) - - Button("OK") { + /* + Button(SwiftLocalizationHelper.localizedString(forKey: "OK")) { presentationMode.wrappedValue.dismiss() } .padding() @@ -93,7 +94,15 @@ public struct AboutView: View { .foregroundColor(.white) .cornerRadius(12) .frame(height: 33) - .frame(minWidth: 100) + .frame(minWidth: 100)*/ + Button(SwiftLocalizationHelper.localizedString(forKey: "OK")) { + aboutVC.dismiss(animated:true) + } + .padding() + .background(Color.blue) + .foregroundColor(.white) + .cornerRadius(12) + .frame(height: 33) } .padding(.top, 10) } @@ -101,3 +110,4 @@ public struct AboutView: View { .padding() } } + diff --git a/VoidLink/AboutViewController.swift b/VoidLink/AboutViewController.swift index be751ec2..ea1fdcb6 100644 --- a/VoidLink/AboutViewController.swift +++ b/VoidLink/AboutViewController.swift @@ -13,8 +13,9 @@ import SwiftUI @objc class AboutViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - - let hostingVC = UIHostingController(rootView: AboutView()) + + let hostingVC = UIHostingController(rootView: AboutView( aboutVC: self)) + addChild(hostingVC) hostingVC.view.translatesAutoresizingMaskIntoConstraints = false view.addSubview(hostingVC.view) @@ -29,7 +30,6 @@ import SwiftUI // 🎯 设置弹窗大小 preferredContentSize = CGSize(width: 530, height: 450) - //preferredContentSize = CGSize(width:150, height:120 ) // ⚠️ 一定要设置以下样式才会生效 preferredContentSize modalPresentationStyle = .formSheet diff --git a/VoidLink/ComputerScrollView.h b/VoidLink/ComputerScrollView.h deleted file mode 100644 index 16a93cef..00000000 --- a/VoidLink/ComputerScrollView.h +++ /dev/null @@ -1,13 +0,0 @@ -// -// ComputerScrollView.h -// Moonlight -// -// Created by Diego Waxemberg on 9/30/15. -// Copyright © 2015 Moonlight Stream. All rights reserved. -// - -#import - -@interface ComputerScrollView : UIScrollView - -@end diff --git a/VoidLink/ComputerScrollView.m b/VoidLink/ComputerScrollView.m deleted file mode 100644 index c9610170..00000000 --- a/VoidLink/ComputerScrollView.m +++ /dev/null @@ -1,28 +0,0 @@ -// -// 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 diff --git a/VoidLink/HostCardView.m b/VoidLink/HostCardView.m index 9081bb2b..ff4852e2 100644 --- a/VoidLink/HostCardView.m +++ b/VoidLink/HostCardView.m @@ -505,7 +505,7 @@ static const float REFRESH_CYCLE = 2.0f; - (void) updateLoop { // Stop immediately if the view has been detached - if (self.superview == nil) { + if (self.superview == nil || [self.delegate isStreaming]) { return; } @@ -514,7 +514,7 @@ static const float REFRESH_CYCLE = 2.0f; [self updateContentsForHost:_host]; // Queue the next refresh cycle - if(![self.delegate isStreaming]) [self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE]; + [self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE]; } - (void) updateContentsForHost:(TemporaryHost*)host { diff --git a/VoidLink/Input/CommandManager.swift b/VoidLink/Input/CommandManager.swift index 5a2c239d..d07cc750 100644 --- a/VoidLink/Input/CommandManager.swift +++ b/VoidLink/Input/CommandManager.swift @@ -417,7 +417,7 @@ import UIKit print("No match found for input: \(input)") return nil } - print("Regex matched for input: \(input)") + // print("Regex matched for input: \(input)") let matchedString = (input as NSString).substring(with: match.range(at: 0)) let keyStrings = matchedString.split(separator: "+").map { String($0) } @@ -475,7 +475,7 @@ import UIKit print("No match found for input: \(input)") return nil } - print("Regex matched for input: \(input)") + // print("Regex matched for input: \(input)") let matchedString = (input as NSString).substring(with: match.range(at: 0)) let cmdStrings = matchedString.split(separator: "-").map { String($0) } diff --git a/VoidLink/Input/CustomOSC/OSCProfilesManager.h b/VoidLink/Input/CustomOSC/OSCProfilesManager.h index 58cc6bf3..7feb0711 100644 --- a/VoidLink/Input/CustomOSC/OSCProfilesManager.h +++ b/VoidLink/Input/CustomOSC/OSCProfilesManager.h @@ -22,8 +22,10 @@ NS_ASSUME_NONNULL_BEGIN @property NSMutableArray *currentProfiles; -+ (OSCProfilesManager *) sharedManager:(CGRect)viewBounds; -+ (void) setOnScreenWidgetViewsSet:(NSMutableSet* )set; ++ (OSCProfilesManager *)sharedManager:(CGRect)viewBounds; ++ (void)setOnScreenWidgetViewsSet:(NSMutableSet* )set; ++ (void)setLayoutViewBounds:(CGRect)bounds; + #pragma mark - Getters /** diff --git a/VoidLink/Input/CustomOSC/OSCProfilesManager.m b/VoidLink/Input/CustomOSC/OSCProfilesManager.m index bc1e0141..ab8fd1fa 100644 --- a/VoidLink/Input/CustomOSC/OSCProfilesManager.m +++ b/VoidLink/Input/CustomOSC/OSCProfilesManager.m @@ -18,15 +18,15 @@ @implementation OSCProfilesManager static NSMutableSet *OnScreenWidgetViews; -static CGRect streamViewBounds; +static CGRect layoutViewBounds; #pragma mark - Initializer + (OSCProfilesManager *) sharedManager:(CGRect)viewBounds { static OSCProfilesManager *_sharedManager = nil; static dispatch_once_t onceToken; - streamViewBounds = viewBounds; - NSLog(@"bounds width: %f, height: %f", streamViewBounds.size.width, streamViewBounds.size.height); + layoutViewBounds = viewBounds; + // NSLog(@"bounds width: %f, height: %f", layoutViewBounds.size.width, layoutViewBounds.size.height); dispatch_once(&onceToken, ^{ _sharedManager = [[self alloc] init]; }); @@ -38,10 +38,14 @@ static CGRect streamViewBounds; #pragma mark - Class Helper Methods -+ (void) setOnScreenWidgetViewsSet:(NSMutableSet* )set{ ++ (void)setOnScreenWidgetViewsSet:(NSMutableSet* )set{ OnScreenWidgetViews = set; } ++ (void)setLayoutViewBounds:(CGRect)bounds{ + layoutViewBounds = bounds; +} + /** * Returns the profile whose 'name' property has a value that is equal to the 'name' passed into the method */ @@ -297,17 +301,21 @@ static CGRect streamViewBounds; } - (CGPoint)normalizeWidgetPosition:(CGPoint)position { + CGPoint newPosition = position; if(position.x > 1.0 && position.y >1.0){ - position.x = position.x / streamViewBounds.size.width; - position.y = position.y / streamViewBounds.size.height; + position.x = position.x / layoutViewBounds.size.width; + position.y = position.y / layoutViewBounds.size.height; } + // asdfsda; + NSLog(@"sef.view bounds: %f, %f", layoutViewBounds.size.width, layoutViewBounds.size.height); + NSLog(@"position: %f, %f, denormalized position: %f, %f", position.x, position.y, newPosition.x, newPosition.y); return position; } - (CGPoint)denormalizeWidgetPosition:(CGPoint)position { if(position.x < 1.0 && position.y < 1.0){ - position.x = position.x * streamViewBounds.size.width; - position.y = position.y * streamViewBounds.size.height; + position.x = position.x * layoutViewBounds.size.width; + position.y = position.y * layoutViewBounds.size.height; } return position; } diff --git a/VoidLink/Input/NativeTouchHandler.m b/VoidLink/Input/NativeTouchHandler.m index b5871fb5..95f90a0e 100644 --- a/VoidLink/Input/NativeTouchHandler.m +++ b/VoidLink/Input/NativeTouchHandler.m @@ -35,7 +35,6 @@ NSMutableSet *pointerIdPool; //pre-defined pool of pointerIds. NSMutableSet *unassignedPointerIds; NSMutableSet *blacklistedTouches; - bool doNotBlockTouchEvents; NSMutableDictionary *pointerObjDict; @@ -61,7 +60,6 @@ } self->activePointerIds = [NSMutableSet set]; self->blacklistedTouches = [NSMutableSet set]; - doNotBlockTouchEvents = true; self->asyncNativeTouch = settings.asyncNativeTouchPriority.intValue != AsyncNativeTouchOff; @@ -160,15 +158,14 @@ NSNumber* touchAddrObj = @((uintptr_t)touch); unassignedPointerIds = [pointerIdPool mutableCopy]; //reset unassignedPointerIds [unassignedPointerIds minusSet:activePointerIds]; - uint8_t pointerId = [[unassignedPointerIds anyObject] unsignedIntValue]; - [pointerIdDict setObject:@(pointerId) forKey:touchAddrObj]; - [activePointerIds addObject:@(pointerId)]; + NSNumber* pointerIdObj = @([[unassignedPointerIds anyObject] unsignedIntValue]); + [pointerIdDict setObject:pointerIdObj forKey:touchAddrObj]; + [activePointerIds addObject:pointerIdObj]; //check if touch point is spawned on the left or right upper half screen edges, event to remote PC. this is for better handling in-stream slide gesture CGPoint initialPoint = [touch locationInView:self->streamView]; if(initialPoint.y < slideGestureVerticalThreshold && (initialPoint.x < EDGE_TOLERANCE || initialPoint.x > screenWidthWithThreshold)) { - doNotBlockTouchEvents = false; - // [blacklistedTouches addObject:touchAddrObj]; + [blacklistedTouches addObject:touchAddrObj]; } } @@ -192,8 +189,8 @@ - (void)sendTouchEvent:(UITouch*)touch withTouchtype:(uint8_t)touchType{ //if(touchPointSpawnedAtUpperScreenEdge && touchType != LI_TOUCH_EVENT_UP) return; // we're done here. this touch event will not be sent to the remote PC. and this must be checked after coord selector finishes populating new relative coords, or the app will crash - // if([blacklistedTouches containsObject:@((uintptr_t)touch)]) return; - + if([blacklistedTouches containsObject:@((uintptr_t)touch)]) return; + CGPoint targetCoords; //NSLog(@"selecting coords: %d", touch.phase == UITouchPhaseMoved); // NSLog(@"excluded count: %d", (uint32_t)[excludedPointerIds count]); @@ -239,7 +236,7 @@ // continue to the next loop if current touch is already captured by OSC. works only in regular native touch if([OnScreenControls.touchAddrsCapturedByOnScreenControls containsObject:@((uintptr_t)touch)]) continue; if(self->activateCoordSelector) [self updatePointerObjInDict:touch]; - if(self->doNotBlockTouchEvents) [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_MOVE]; + [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_MOVE]; [[self getPointerObjFromDict:touch] doesNeedResetCoords]; // execute the judging of doesReachBoundary for current pointer instance. (happens after the event is sent to Sunshine service) usleep(self->touchMoveEventIntervalUs); } @@ -265,9 +262,8 @@ [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_UP]; //send touch event before remove pointerId [self removePointerId:touch]; //then remove pointerId if(self->activateCoordSelector) [self removePointerObjFromDict:touch]; - //[self->blacklistedTouches removeObject:@((uintptr_t)touch)]; + [self->blacklistedTouches removeObject:@((uintptr_t)touch)]; } - self->doNotBlockTouchEvents = true; //if(self->touchPointSpawnedAtUpperScreenEdge && [[event allTouches] count] == [touches count]) }); else{ @@ -297,10 +293,10 @@ } - (void)removePointerObjFromDict:(UITouch*)touch{ - uintptr_t memAddrValue = (uintptr_t)touch; - NativeTouchPointer* pointer = [pointerObjDict objectForKey:@(memAddrValue)]; + NSNumber* touchAddrObj = @((uintptr_t)touch); + NativeTouchPointer* pointer = [pointerObjDict objectForKey:touchAddrObj]; if(pointer != nil){ - [pointerObjDict removeObjectForKey:@(memAddrValue)]; + [pointerObjDict removeObjectForKey:touchAddrObj]; } } diff --git a/VoidLink/Input/OnScreenControls.m b/VoidLink/Input/OnScreenControls.m index 13b585ba..8ef5c01b 100644 --- a/VoidLink/Input/OnScreenControls.m +++ b/VoidLink/Input/OnScreenControls.m @@ -343,7 +343,7 @@ static float L3_Y; if(position.x < 1.0 && position.y < 1.0) { position.x = position.x * _view.bounds.size.width; position.y = position.y * _view.bounds.size.height; - NSLog(@"denormalizing position: %f, %f", position.x, position.y); + // NSLog(@"denormalizing position: %f, %f", position.x, position.y); } return position; } @@ -1560,7 +1560,7 @@ static float L3_Y; // on screen at the time // DZ capturing shall be refactored in CustomOSC Mode & non-default profile condition - if(self._level == OnScreenControlsLevelCustom && [profilesManager getIndexOfSelectedProfile] != 0){ + if(self._level == OnScreenControlsLevelCustom){ CGPoint touchLocation = [touch locationInView:_view]; for (NSString *key in _activeCustomOscButtonPositionDict) { NSValue *value = _activeCustomOscButtonPositionDict[key]; @@ -1930,7 +1930,7 @@ static float L3_Y; if(alpha < 0.23) targetAlpha = 0.23; if(alpha == 0.0 || alpha == 1.0) targetAlpha = 5.0f/6.0f; // invalid alpha value - NSLog(@"alphas: %f",targetAlpha); + // NSLog(@"alphas: %f",targetAlpha); if (layer == self._aButton || layer == self._bButton || diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index cca8b716..48bf2aac 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -472,7 +472,7 @@ import UIKit if vibrationOn { vibrationGenerator.prepare() vibrationGenerator.impactOccurred() - print("vibrationInstance: \(vibrationGenerator)") + // print("vibrationInstance: \(vibrationGenerator)") } return indicatorBorder @@ -864,7 +864,7 @@ import UIKit if vibrationOn { vibrationGenerator.prepare() vibrationGenerator.impactOccurred() - print("vibrationInstance: \(vibrationGenerator)") + // print("vibrationInstance: \(vibrationGenerator)") } CATransaction.commit() } @@ -1138,8 +1138,8 @@ import UIKit let offsetX = currentLocation.x - latestTouchLocation.x; let offsetY = currentLocation.y - latestTouchLocation.y; - let outOfBoundsX = center.x+offsetX > (self.superview?.bounds.width)! || center.x+offsetX < 0 - let outOfBoundsY = center.y+offsetY > (self.superview?.bounds.height)! || center.y+offsetY < 0 + let outOfBoundsX = center.x+offsetX >= (self.superview?.bounds.width)! || center.x+offsetX < 0 + let outOfBoundsY = center.y+offsetY >= (self.superview?.bounds.height)! || center.y+offsetY < 0 center = CGPoint(x: outOfBoundsX ? center.x : center.x+offsetX, y: outOfBoundsY ? center.y : center.y+offsetY) diff --git a/VoidLink/Input/PureNativeTouchHandler.m b/VoidLink/Input/PureNativeTouchHandler.m index 27c58962..d1e9df14 100644 --- a/VoidLink/Input/PureNativeTouchHandler.m +++ b/VoidLink/Input/PureNativeTouchHandler.m @@ -34,7 +34,6 @@ NSMutableSet *pointerIdPool; //pre-defined pool of pointerIds. NSMutableSet *unassignedPointerIds; NSMutableSet *blacklistedTouches; - bool doNotBlockTouchEvents; NSMutableDictionary *pointerObjDict; @@ -60,8 +59,7 @@ } self->activePointerIds = [NSMutableSet set]; self->blacklistedTouches = [NSMutableSet set]; - doNotBlockTouchEvents = true; - + self->asyncNativeTouch = settings.asyncNativeTouchPriority.intValue != AsyncNativeTouchOff; switch(settings.asyncNativeTouchPriority.intValue){ @@ -159,15 +157,14 @@ NSNumber* touchAddrObj = @((uintptr_t)touch); unassignedPointerIds = [pointerIdPool mutableCopy]; //reset unassignedPointerIds [unassignedPointerIds minusSet:activePointerIds]; - uint8_t pointerId = [[unassignedPointerIds anyObject] unsignedIntValue]; - [pointerIdDict setObject:@(pointerId) forKey:touchAddrObj]; - [activePointerIds addObject:@(pointerId)]; + NSNumber* pointerIdObj = @([[unassignedPointerIds anyObject] unsignedIntValue]); + [pointerIdDict setObject:pointerIdObj forKey:touchAddrObj]; + [activePointerIds addObject:pointerIdObj]; //check if touch point is spawned on the left or right upper half screen edges, event to remote PC. this is for better handling in-stream slide gesture CGPoint initialPoint = [touch locationInView:self->streamView]; if(initialPoint.y < slideGestureVerticalThreshold && (initialPoint.x < EDGE_TOLERANCE || initialPoint.x > screenWidthWithThreshold)) { - doNotBlockTouchEvents = false; - // [blacklistedTouches addObject:touchAddrObj]; + [blacklistedTouches addObject:touchAddrObj]; } } @@ -191,8 +188,8 @@ - (void)sendTouchEvent:(UITouch*)touch withTouchtype:(uint8_t)touchType{ //if(touchPointSpawnedAtUpperScreenEdge && touchType != LI_TOUCH_EVENT_UP) return; // we're done here. this touch event will not be sent to the remote PC. and this must be checked after coord selector finishes populating new relative coords, or the app will crash - // if([blacklistedTouches containsObject:@((uintptr_t)touch)]) return; - + if([blacklistedTouches containsObject:@((uintptr_t)touch)]) return; + CGPoint targetCoords; //NSLog(@"selecting coords: %d", touch.phase == UITouchPhaseMoved); // NSLog(@"excluded count: %d", (uint32_t)[excludedPointerIds count]); @@ -235,14 +232,13 @@ for (UITouch* touch in touches){ // continue to the next loop if current touch is already captured by OSC. works only in regular native touch if(self->activateCoordSelector) [self updatePointerObjInDict:touch]; - if(self->doNotBlockTouchEvents) [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_MOVE]; + [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_MOVE]; [[self getPointerObjFromDict:touch] doesNeedResetCoords]; // execute the judging of doesReachBoundary for current pointer instance. (happens after the event is sent to Sunshine service) usleep(self->touchMoveEventIntervalUs); } }); else { for (UITouch* touch in touches){ - // continue to the next loop if current touch is already captured by OSC. works only in regular native touch if(self->activateCoordSelector) [self updatePointerObjInDict:touch]; [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_MOVE]; [[self getPointerObjFromDict:touch] doesNeedResetCoords]; // execute the judging of doesReachBoundary for current pointer instance. (happens after the event is sent to Sunshine service) @@ -259,9 +255,8 @@ [self sendTouchEvent:touch withTouchtype:LI_TOUCH_EVENT_UP]; //send touch event before remove pointerId [self removePointerId:touch]; //then remove pointerId if(self->activateCoordSelector) [self removePointerObjFromDict:touch]; - //[self->blacklistedTouches removeObject:@((uintptr_t)touch)]; + [self->blacklistedTouches removeObject:@((uintptr_t)touch)]; } - self->doNotBlockTouchEvents = true; //if(self->touchPointSpawnedAtUpperScreenEdge && [[event allTouches] count] == [touches count]) }); else{ @@ -290,10 +285,10 @@ } - (void)removePointerObjFromDict:(UITouch*)touch{ - uintptr_t memAddrValue = (uintptr_t)touch; - NativeTouchPointer* pointer = [pointerObjDict objectForKey:@(memAddrValue)]; + NSNumber* touchAddrObj = @((uintptr_t)touch); + NativeTouchPointer* pointer = [pointerObjDict objectForKey:touchAddrObj]; if(pointer != nil){ - [pointerObjDict removeObjectForKey:@(memAddrValue)]; + [pointerObjDict removeObjectForKey:touchAddrObj]; } } @@ -308,3 +303,4 @@ } @end + diff --git a/VoidLink/Input/StreamView.h b/VoidLink/Input/StreamView.h index 1fff07fc..a65e866f 100644 --- a/VoidLink/Input/StreamView.h +++ b/VoidLink/Input/StreamView.h @@ -36,6 +36,7 @@ @property (assign, nonatomic) UIView* streamFrameTopLayerView; @property (assign, nonatomic) CGFloat streamAspectRatio; @property (assign, nonatomic) CGRect originalFrame; +@property (assign, nonatomic) bool widgetToolOpened; - (void) setupStreamView:(ControllerSupport*)controllerSupport @@ -50,7 +51,7 @@ andConfig:(StreamConfiguration*)streamConfig; - (void) reloadOnScreenControlsWith:(ControllerSupport*)controllerSupport andConfig:(StreamConfiguration*)streamConfig; -- (void) clearOnScreenKeyboardButtons; +- (void) clearOnScreenWidgets; - (void) reloadOnScreenWidgetViews; - (CGSize) getVideoAreaSize; diff --git a/VoidLink/Input/StreamView.m b/VoidLink/Input/StreamView.m index ee85b678..92ae7144 100644 --- a/VoidLink/Input/StreamView.m +++ b/VoidLink/Input/StreamView.m @@ -34,7 +34,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; @implementation StreamView { UIView* streamFrameTopLayerView; TemporarySettings* settings; - + OnScreenControls* onScreenControls; KeyboardInputField* keyInputField; @@ -43,7 +43,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; float streamAspectRatio; - + // iOS 13.4 mouse support NSInteger lastMouseButtonMask; float lastMouseX; @@ -56,7 +56,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; double accumulatedMouseDeltaY; int localMousePointerMode; - + UIResponder* touchHandler; id interactionDelegate; @@ -72,7 +72,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; #endif CGFloat HeightViewLiftedTo; UILabel* keyboardToggleTip; - + UIKeyModifierFlags comboKeyModifierFlags; } @@ -87,9 +87,9 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; self->interactionDelegate = interactionDelegate; self->streamAspectRatio = (float)streamConfig.width / (float)streamConfig.height; self.streamAspectRatio = self->streamAspectRatio; - + settings = [[[DataManager alloc] init] getSettings]; - + localMousePointerMode = streamConfig.localMousePointerMode; keysDown = [[NSMutableSet alloc] init]; @@ -114,18 +114,18 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; keyboardToggleTip.layer.cornerRadius = 10; keyboardToggleTip.clipsToBounds = true; NSLog(@"setup streamView %f", CACurrentMediaTime()); - + // if(settings.touchMode.intValue == NativeTouchOnly) [self addGestureRecognizer:keyboardToggleRecognizer]; //keep legacy approach in pure native mode // else [self->streamFrameTopLayerView addGestureRecognizer:keyboardToggleRecognizer]; //add to the superview in other modes - + // [self->streamFrameTopLayerView addGestureRecognizer:keyboardToggleRecognizer]; //add to the superview in other modes - + #if TARGET_OS_TV // tvOS requires RelativeTouchHandler to manage Apple Remote input self->touchHandler = [[RelativeTouchHandler alloc] initWithView:self]; #else // iOS uses touch Mode depending on user preference - + switch (settings.touchMode.intValue) { case NativeTouch: keyboardToggleRecognizer.immediateTriggering = false; @@ -142,11 +142,11 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; self->touchHandler = [[AbsoluteTouchHandler alloc] initWithView:self]; keyboardToggleRecognizer.immediateTriggering = true; //triggers signal in touchesBegan callback stage break; - + default: break; } - + // we'll render on-screen controls on the toplayer too: onScreenControls = [[OnScreenControls alloc] initWithView:self->streamFrameTopLayerView controllerSup:controllerSupport streamConfig:streamConfig]; // don't delete, this is mandatory /* @@ -155,15 +155,15 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; RelativeTouchHandler* relativeTouchHandler = (RelativeTouchHandler*) touchHandler; onScreenControls.mouseRightClickTapRecognizer = relativeTouchHandler.mouseRightClickTapRecognizer; } */ - + OnScreenControlsLevel level = (OnScreenControlsLevel)[settings.onscreenControls integerValue]; if (settings.touchMode.intValue != RelativeTouch && settings.touchMode.intValue != NativeTouch ) { Log(LOG_I, @"On-screen controls disabled in non-relative touch mode"); [onScreenControls setLevel:OnScreenControlsLevelOff]; - + //pass touchesCaptureByOnScreenButtons Set to the native touchhandler, this NSSet is init witihin onscreencontrols class, don't do it again in native touch handler class [OnScreenControls.touchAddrsCapturedByOnScreenControls removeAllObjects]; // reset the attribute to nil - + /* if(settings.touchMode.intValue == NativeTouch){ NativeTouchHandler* nativeTouchHandler = (NativeTouchHandler* )touchHandler; @@ -302,7 +302,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; UIBarButtonItem *altBarButton = [self createButtonWithImageNamed:@"AltIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:0x12 isToggleable:YES]; UIBarButtonItem *deleteBarButton = [self createButtonWithImageNamed:@"DeleteIcon.png" backgroundColor:[UIColor blackColor] target:self action:@selector(toolbarButtonClicked:) keyCode:0x2E isToggleable:NO]; UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:nil action:nil]; - + [customToolbarView setItems:[NSArray arrayWithObjects:doneBarButton, windowsBarButton, escapeBarButton, tabBarButton, shiftBarButton, controlBarButton, altBarButton, deleteBarButton, flexibleSpace, nil]]; keyInputField.inputAccessoryView = customToolbarView; } @@ -311,7 +311,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; [keyInputField addTarget:self action:@selector(onKeyboardPressed:) forControlEvents:UIControlEventEditingChanged]; // Undo causes issues for our state management, so turn it off [keyInputField.undoManager disableUndoRegistration]; - + //[keyboardToggleTip removeFromSuperview]; } } @@ -350,7 +350,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (void) showOnScreenControls { #if !TARGET_OS_TV - [onScreenControls show]; + if(!_widgetToolOpened) [onScreenControls show]; #endif } @@ -385,13 +385,13 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (void) reloadOnScreenControlsWith:(ControllerSupport*)controllerSupport andConfig:(StreamConfiguration*)streamConfig { - + // we'll render on-screen controllers on the toplayer too. onScreenControls = [[OnScreenControls alloc] initWithView:self->streamFrameTopLayerView controllerSup:controllerSupport streamConfig:streamConfig]; /* // pass mouseRightClickTapRecognizer to onScreenControls obj here: if([self isOscEnabled]){ - + RelativeTouchHandler* relativeTouchHandler = (RelativeTouchHandler *)touchHandler; onScreenControls.mouseRightClickTapRecognizer = relativeTouchHandler.mouseRightClickTapRecognizer; } */ @@ -399,7 +399,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; } -- (void) clearOnScreenKeyboardButtons{ +- (void) clearOnScreenWidgets{ for (UIView *subview in self->streamFrameTopLayerView.subviews) { // 检查子视图是否是特定类型的实例 if ([subview isKindOfClass:[OnScreenWidgetView class]]) { @@ -411,23 +411,26 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (CGPoint)denormalizeWidgetPosition:(CGPoint)position { if(position.x < 1.0 && position.y < 1.0){ - position.x = position.x * self.bounds.size.width; - position.y = position.y * self.bounds.size.height; + position.x = position.x * streamFrameTopLayerView.bounds.size.width; + position.y = position.y * streamFrameTopLayerView.bounds.size.height; + } + else{ + NSLog(@"invalid coords"); } return position; } - (void) reloadOnScreenWidgetViews{ - + // NSLog(@"reload on screen keyboard buttons here"); // remove all keyboard widget views first - [self clearOnScreenKeyboardButtons]; - + [self clearOnScreenWidgets]; + // bool customOscEnabled = [self isOscEnabled] && settings.onscreenControls.intValue == OnScreenControlsLevelCustom; - + if(![self isOnScreenButtonEnabled]) return; - + OSCProfilesManager* profilesManager = [OSCProfilesManager sharedManager: self.bounds]; OSCProfile *oscProfile = [profilesManager getSelectedProfile]; //returns the currently selected OSCProfile @@ -630,7 +633,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; } } } - + #endif if ([self handleMouseButtonEvent:BUTTON_ACTION_PRESS forTouches:touches @@ -710,8 +713,8 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; } - (BOOL)handleMouseButtonEvent:(int)buttonAction forTouches:(NSSet *)touches withEvent:(UIEvent *)event { - - + + // NSLog(@"mouse click time: %f", CACurrentMediaTime()*1000); #if !TARGET_OS_TV if (@available(iOS 13.4, *)) { @@ -775,12 +778,12 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { #if !TARGET_OS_TV - + if (settings.touchMode.intValue == NativeTouchOnly) { [touchHandler touchesMoved:touches withEvent:event]; return; //This is a native touch oriented fork, in pure native touch mode, this call back method deals with native touch only. } - + for (UITouch* touch in touches) { if (touch.type == UITouchTypePencil) { if ([self sendStylusEvent:touch]) return; @@ -806,7 +809,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; } #endif } - + hasUserInteracted = YES; if(self->settings.touchMode.intValue == NativeTouch || self->settings.touchMode.intValue == RelativeTouch){ @@ -884,7 +887,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; [touchHandler touchesEnded:touches withEvent:event]; return; //This is a native touch oriented fork, in pure native touch mode, this call back method deals with native touch only. } - + if (@available(iOS 13.4, *)){ //now only pencil events are restricted for (UITouch* touch in touches) { if (touch.type == UITouchTypePencil) { diff --git a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents index bb37533b..616b9294 100644 --- a/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents +++ b/VoidLink/Limelight.xcdatamodeld/VoidLink v1.0.xcdatamodel/contents @@ -44,7 +44,7 @@ - + diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index d5129bae..0183d2e4 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -295,13 +295,13 @@ "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "[ 開啟螢幕小工具 ]" + "value" : "[ 調整螢幕小工具版面配置 ]" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "[ 開啟螢幕小工具 ]" + "value" : "[ 調整螢幕小工具版面配置 ]" } } } @@ -1457,25 +1457,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/uscwmv3vz8g30rmk?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/uscwmv3vz8g30rmk?singleDoc" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc" } }, "zh-Hant" : { "stringUnit" : { - "state" : "needs_review", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc#" + "state" : "translated", + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc" } }, "zh-HK" : { "stringUnit" : { - "state" : "needs_review", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc#" + "state" : "translated", + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc" } } } @@ -1705,25 +1705,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bu3hki4pezy93g6r?singleDoc# " + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bu3hki4pezy93g6r?singleDoc" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/cqbse6t4o6f9hil1?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/cqbse6t4o6f9hil1?singleDoc" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/cqbse6t4o6f9hil1?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/cqbse6t4o6f9hil1?singleDoc" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/cqbse6t4o6f9hil1?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/cqbse6t4o6f9hil1?singleDoc" } } } @@ -2022,25 +2022,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/uscwmv3vz8g30rmk?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/uscwmv3vz8g30rmk?singleDoc" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/bz6ggagp0ly4loq3?singleDoc" } } } @@ -2454,25 +2454,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zdf5l29s3vohs6iq?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zdf5l29s3vohs6iq?singleDoc" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/yfao3s5bhl93rs01?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/yfao3s5bhl93rs01?singleDoc" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/yfao3s5bhl93rs01?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/yfao3s5bhl93rs01?singleDoc" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/yfao3s5bhl93rs01?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/yfao3s5bhl93rs01?singleDoc" } } } @@ -2898,6 +2898,29 @@ } } }, + "Offline\n%@" : { + "extractionState" : "manual", + "localizations" : { + "zh-Hans" : { + "stringUnit" : { + "state" : "translated", + "value" : "离线\n%@" + } + }, + "zh-Hant" : { + "stringUnit" : { + "state" : "translated", + "value" : "離線\n%@" + } + }, + "zh-HK" : { + "stringUnit" : { + "state" : "translated", + "value" : "離線\n%@" + } + } + } + }, "Ok" : { "extractionState" : "manual", "localizations" : { @@ -2990,48 +3013,48 @@ } } }, - "Online - Not Paired" : { + "Online - Not Paired\n%@" : { "extractionState" : "manual", "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在线 - 未配对" + "value" : "在线 - 未配对\n%@" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "線上 - 未配對" + "value" : "線上 - 未配對\n%@" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "線上 - 未配對" + "value" : "線上 - 未配對\n%@" } } } }, - "Online - Paired" : { + "Online - Paired\n%@" : { "extractionState" : "manual", "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "在线 - 已配对" + "value" : "在线 - 已配对\n%@" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "線上 - 已配對" + "value" : "線上 - 已配對\n%@" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "線上 - 已配對" + "value" : "線上 - 已配對\n%@" } } } @@ -3065,19 +3088,19 @@ "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zrg0ga93avz4s747?singleDoc# " + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zrg0ga93avz4s747?singleDoc" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zrg0ga93avz4s747?singleDoc# " + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zrg0ga93avz4s747?singleDoc" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zrg0ga93avz4s747?singleDoc# " + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/zrg0ga93avz4s747?singleDoc" } } } @@ -4240,25 +4263,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/rgc9if4xrf352555?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/rgc9if4xrf352555?singleDoc" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/ok4egvu4lt37wc1f?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/ok4egvu4lt37wc1f?singleDoc" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/ok4egvu4lt37wc1f?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/ok4egvu4lt37wc1f?singleDoc" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/ok4egvu4lt37wc1f?singleDoc#" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/ok4egvu4lt37wc1f?singleDoc" } } } @@ -4344,25 +4367,25 @@ "en" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/dhmg3h27ls8mwt4a?singleDoc# 《About VoidLink》" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/dhmg3h27ls8mwt4a?singleDoc" } }, "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/fdi4rxkxykhl5zpp?singleDoc# 《关于 VoidLink》" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/fdi4rxkxykhl5zpp?singleDoc" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/fdi4rxkxykhl5zpp?singleDoc# 《关于 VoidLink》" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/fdi4rxkxykhl5zpp?singleDoc" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/fdi4rxkxykhl5zpp?singleDoc# 《关于 VoidLink》" + "value" : "https://voidlink.yuque.com/org-wiki-voidlink-znirha/fa3tgr/fdi4rxkxykhl5zpp?singleDoc" } } } @@ -4603,25 +4626,25 @@ } } }, - "Touch & Control" : { + "Touch & Controller" : { "extractionState" : "manual", "localizations" : { "zh-Hans" : { "stringUnit" : { "state" : "translated", - "value" : "触屏与控制" + "value" : "触屏与手柄" } }, "zh-Hant" : { "stringUnit" : { "state" : "translated", - "value" : "觸控與控制" + "value" : "觸控與控制器" } }, "zh-HK" : { "stringUnit" : { "state" : "translated", - "value" : "觸控與控制" + "value" : "觸控與控制器" } } } diff --git a/VoidLink/Stream/Connection.h b/VoidLink/Stream/Connection.h index 319ab5fc..b7327b58 100644 --- a/VoidLink/Stream/Connection.h +++ b/VoidLink/Stream/Connection.h @@ -12,7 +12,7 @@ #import "BandwidthTracker.h" #import "Plot.h" -#define CONN_TEST_SERVER "ios.conntest.moonlight-stream.org" +#define CONN_TEST_SERVER "www.baidu.com" @interface Connection : NSOperation diff --git a/VoidLink/UIAppView.m b/VoidLink/UIAppView.m index b02538b8..54d9793b 100644 --- a/VoidLink/UIAppView.m +++ b/VoidLink/UIAppView.m @@ -260,7 +260,7 @@ static UIImage* noImage; - (void) updateLoop { // Stop immediately if the view has been detached - if (self.superview == nil) { + if (self.superview == nil || ![self.updateLoopDelegate isInAppView]) { return; } @@ -282,7 +282,7 @@ static UIImage* noImage; [self setAlpha:_app.hidden ? 0.4 : 1.0]; // Queue the next refresh cycle - if([self.updateLoopDelegate isInAppView]) [self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE]; + [self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE]; } @end diff --git a/VoidLink/UIComputerView.h b/VoidLink/UIComputerView.h deleted file mode 100644 index 1e5c6a1a..00000000 --- a/VoidLink/UIComputerView.h +++ /dev/null @@ -1,29 +0,0 @@ -// -// UIComputerView.h -// Moonlight -// -// Created by Diego Waxemberg on 10/22/14. -// Copyright (c) 2014 Moonlight Stream. All rights reserved. -// - -#import -#import "TemporaryHost.h" - -@protocol HostCallback - -- (void) noneUserInitiatedHostAction:(TemporaryHost*)host view:(UIView*)view; -- (void) hostCardLongPressed:(TemporaryHost*)host view:(UIView*)view; -- (void) addHostTapped; - -@end - -#if !TARGET_OS_TV -@interface UIComputerView : UIButton -#else -@interface UIComputerView : UIButton -#endif - -- (id) initWithComputer:(TemporaryHost*)host andCallback:(id)callback; -- (id) initForAddWithCallback:(id)callback; - -@end diff --git a/VoidLink/UIComputerView.m b/VoidLink/UIComputerView.m index ab6ec68a..e69de29b 100644 --- a/VoidLink/UIComputerView.m +++ b/VoidLink/UIComputerView.m @@ -1,244 +0,0 @@ -// -// UIComputerView.m -// Moonlight -// -// Created by Diego Waxemberg on 10/22/14. -// Copyright (c) 2014 Moonlight Stream. All rights reserved. -// -// Modified by True砖家 since 2024.6.30 -// Copyright © 2024 True砖家 @ Bilibili. All rights reserved. -// -// - -#import "UIComputerView.h" -#import "LocalizationHelper.h" - -@implementation UIComputerView { - TemporaryHost* _host; - UIImageView* _hostIcon; - UILabel* _hostLabel; - UIImageView* _hostOverlay; - UIActivityIndicatorView* _hostSpinner; - id _callback; - CGSize _labelSize; -} -static const float REFRESH_CYCLE = 2.0f; - -#if TARGET_OS_TV -static const int ITEM_PADDING = 50; -static const int LABEL_DY = 40; -#else -static const int ITEM_PADDING = 0; -static const int LABEL_DY = 20; -#endif - -- (id) init { - self = [super init]; - -#if TARGET_OS_TV - self.frame = CGRectMake(0, 0, 400, 400); -#else - if ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad) { - self.frame = CGRectMake(0, 0, 200, 200); - } else { - self.frame = CGRectMake(0, 0, 100, 100); - } -#endif - - _hostIcon = [[UIImageView alloc] initWithFrame:self.frame]; - [_hostIcon setImage:[UIImage imageNamed:@"Computer"]]; - - self.layer.shadowColor = [[UIColor blackColor] CGColor]; - self.layer.shadowOffset = CGSizeMake(5,8); - self.layer.shadowOpacity = 0.3; - - [self addTarget:self action:@selector(hostButtonSelected:) forControlEvents:UIControlEventTouchDown]; - [self addTarget:self action:@selector(hostButtonDeselected:) forControlEvents:UIControlEventTouchUpInside | UIControlEventTouchCancel | UIControlEventTouchDragExit]; - - _hostLabel = [[UILabel alloc] init]; - _hostLabel.textColor = [UIColor whiteColor]; - - _hostOverlay = [[UIImageView alloc] initWithFrame:CGRectMake(self.frame.size.width / 3, _hostIcon.frame.size.height / 4, _hostIcon.frame.size.width / 3, self.frame.size.height / 3)]; - _hostSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleLarge]; - [_hostSpinner setFrame:_hostOverlay.frame]; - _hostSpinner.userInteractionEnabled = NO; - _hostSpinner.hidesWhenStopped = YES; - - [self addSubview:_hostLabel]; - [self addSubview:_hostIcon]; - -#if TARGET_OS_TV - _hostIcon.clipsToBounds = NO; - _hostIcon.adjustsImageWhenAncestorFocused = YES; - _hostIcon.masksFocusEffectToContents = YES; - - self.adjustsImageWhenHighlighted = NO; - - _hostOverlay.masksFocusEffectToContents = YES; - _hostOverlay.adjustsImageWhenAncestorFocused = NO; - - [_hostIcon.overlayContentView addSubview:_hostOverlay]; - [_hostIcon.overlayContentView addSubview:_hostSpinner]; -#else - [self addSubview:_hostOverlay]; - [self addSubview:_hostSpinner]; - - if (@available(iOS 13.4.1, *)) { - // Allow the button style to change when moused over - self.pointerInteractionEnabled = YES; - } -#endif - - return self; -} - -- (void) hostButtonSelected:(id)sender { - _hostIcon.layer.opacity = 0.5f; - _hostSpinner.layer.opacity = 0.5f; - _hostOverlay.layer.opacity = 0.5f; -} -- (void) hostButtonDeselected:(id)sender { - _hostIcon.layer.opacity = 1.0f; - _hostSpinner.layer.opacity = 1.0f; - _hostOverlay.layer.opacity = 1.0f; -} - -- (id) initForAddWithCallback:(id)callback { - self = [self init]; - _callback = callback; - - [self addTarget:self action:@selector(addClicked) forControlEvents:UIControlEventPrimaryActionTriggered]; - - [_hostLabel setText:[LocalizationHelper localizedStringForKey:@"Add Host Manually"]]; - [_hostLabel sizeToFit]; - - [_hostOverlay setImage:[UIImage imageNamed:@"AddOverlayIcon"]]; - - [self updateBounds]; - - return self; -} - -- (id) initWithComputer:(TemporaryHost*)host andCallback:(id)callback { - self = [self init]; - _host = host; - _callback = callback; - - // Use UIContextMenuInteraction on iOS 13.0+ and a standard UILongPressGestureRecognizer - // for tvOS devices and iOS prior to 13.0. -#if !TARGET_OS_TV - if (@available(iOS 13.0, *)) { - UIContextMenuInteraction* rightClickInteraction = [[UIContextMenuInteraction alloc] initWithDelegate:self]; - [self addInteraction:rightClickInteraction]; - } - else -#endif - { - UILongPressGestureRecognizer* longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(hostLongClicked:)]; - [self addGestureRecognizer:longPressRecognizer]; - } - - [self addTarget:self action:@selector(hostClicked) forControlEvents:UIControlEventPrimaryActionTriggered]; - - [self updateContentsForHost:host]; - - return self; -} - -- (void)didMoveToSuperview { - // Start our update loop when we are added to our cell - if (self.superview != nil && _host != nil) { - [self updateLoop]; - } -} - -- (void) updateBounds { - float x = FLT_MAX; - float y = FLT_MAX; - float width = 0; - float height; - - float iconX = _hostIcon.frame.origin.x + _hostIcon.frame.size.width / 2; - _hostLabel.center = CGPointMake(iconX, _hostIcon.frame.origin.y + _hostIcon.frame.size.height + LABEL_DY); - - x = MIN(x, _hostIcon.frame.origin.x); - x = MIN(x, _hostLabel.frame.origin.x); - - y = MIN(y, _hostIcon.frame.origin.y); - y = MIN(y, _hostLabel.frame.origin.y); - - width = MAX(width, _hostIcon.frame.size.width); - width = MAX(width, _hostLabel.frame.size.width); - - height = _hostIcon.frame.size.height + - _hostLabel.frame.size.height + - LABEL_DY / 2; - - self.bounds = CGRectMake(x - ITEM_PADDING, y - ITEM_PADDING, width + 2 * ITEM_PADDING, height + 2 * ITEM_PADDING); -} - -- (void) updateContentsForHost:(TemporaryHost*)host { - _hostLabel.text = _host.name; - [_hostLabel sizeToFit]; - - if (host.state == StateOnline) { - [_hostSpinner stopAnimating]; - - if (host.pairState == PairStateUnpaired) { - [_hostOverlay setImage:[UIImage imageNamed:@"LockedOverlayIcon"]]; - } - else { - [_hostOverlay setImage:nil]; - } - } - else if (host.state == StateOffline) { - [_hostSpinner stopAnimating]; - [_hostOverlay setImage:[UIImage imageNamed:@"ErrorOverlayIcon"]]; - } - else { - [_hostSpinner startAnimating]; - } - - [self updateBounds]; -} - -- (void) updateLoop { - // Stop immediately if the view has been detached - if (self.superview == nil) { - return; - } - - [self updateContentsForHost:_host]; - - // Queue the next refresh cycle - [self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE]; -} - -- (void) hostLongClicked:(UILongPressGestureRecognizer*)gesture { - if (gesture.state == UIGestureRecognizerStateBegan) { - [_callback hostCardLongPressed:_host view:self]; - } -} - -#if !TARGET_OS_TV -- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction - configurationForMenuAtLocation:(CGPoint)location { - // We don't want to trigger the primary action at this point, so cancel - // tracking touch on this view now. This will also have the (intended) - // effect of removing the touch highlight on this view. - [self cancelTrackingWithEvent:nil]; - - [_callback hostCardLongPressed:_host view:self]; - return nil; -} -#endif - -- (void) hostClicked { - [_callback noneUserInitiatedHostAction:_host view:self]; -} - -- (void) addClicked { - [_callback addHostTapped]; -} - -@end diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h index 8215aaab..c2272de5 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h +++ b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.h @@ -27,7 +27,7 @@ NS_ASSUME_NONNULL_BEGIN - (void)presentProfilesTableView; @property LayoutOnScreenControls *layoutOSC; // object that contains a view which contains the on screen controller buttons that allows the user to drag and positions each button on the screen using touch -@property (nonatomic) NSMutableSet* OnScreenWidgetViews; +@property (nonatomic) NSMutableSet* onScreenWidgetViews; @property int OSCSegmentSelected; @property (nonatomic, assign) bool quickSwitchEnabled; diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index fd720ff9..8b847391 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/VoidLink/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -31,6 +31,7 @@ CGRect controllerLoadedBounds; bool widgetViewSelected; bool controllerLayerSelected; + bool viewWillBeResized; __weak IBOutlet NSLayoutConstraint *toolbarTopConstraintiPhone; __weak IBOutlet NSLayoutConstraint *toolbarTopConstraintiPad; UIColor* trashCanStoryBoardColor; @@ -62,7 +63,7 @@ - (void) viewWillDisappear:(BOOL)animated{ OnScreenWidgetView.editMode = false; - for (OnScreenWidgetView* widgetView in self.OnScreenWidgetViews){ + for (OnScreenWidgetView* widgetView in self.onScreenWidgetViews){ [widgetView.stickBallLayer removeFromSuperlayer]; [widgetView.crossMarkLayer removeFromSuperlayer]; } @@ -71,14 +72,23 @@ } - (CGPoint)denormalizeWidgetPosition:(CGPoint)position { + // NSLog(@"position: %f, %f", position.x, position.y); + CGPoint newPosition = position; if(position.x < 1.0 && position.y < 1.0){ - position.x = position.x * self.view.bounds.size.width; - position.y = position.y * self.view.bounds.size.height; + newPosition.x = position.x * self.view.bounds.size.width; + newPosition.y = position.y * self.view.bounds.size.height; } - return position; + return newPosition; } -- (void) reloadOnScreenWidgetViews { +- (void)reloadLegacyOnScreenControls{ + [self.layoutOSC updateControls]; // creates and saves a 'Default' OSC profile or loads the o//ne the user selected on the previous screen + [self addInnerAnalogSticksToOuterAnalogLayers]; + [self.layoutOSC.layoutChanges removeAllObjects]; // since a new OSC profile is being loaded, this will remove all previous layout changes made from the array + [self OSCLayoutChanged]; // fades the 'Undo Button' out +} + +- (void)reloadOnScreenWidgetViews{ NSLog(@"reloadOnScreenWidgets %f", CACurrentMediaTime()); OnScreenWidgetView.editMode = true; [self clearStickIndicator]; @@ -89,7 +99,7 @@ } } - [self.OnScreenWidgetViews removeAllObjects]; + [self.onScreenWidgetViews removeAllObjects]; NSLog(@"reload os Key here"); @@ -120,7 +130,7 @@ [widgetView resizeWidgetView]; // resize must be called after relocation [widgetView adjustTransparencyWithAlpha:buttonState.backgroundAlpha]; [widgetView adjustBorderWithWidth:buttonState.borderWidth]; - [self.OnScreenWidgetViews addObject:widgetView]; + [self.onScreenWidgetViews addObject:widgetView]; } } } @@ -128,11 +138,12 @@ - (void) viewDidLoad { [super viewDidLoad]; profilesManager = [OSCProfilesManager sharedManager:self.view.bounds]; - self.OnScreenWidgetViews = [[NSMutableSet alloc] init]; // will be revised to read persisted data , somewhere else - [OSCProfilesManager setOnScreenWidgetViewsSet:self.OnScreenWidgetViews]; // pass the keyboard button dict to profiles manager + self.onScreenWidgetViews = [[NSMutableSet alloc] init]; // will be revised to read persisted data , somewhere else + [OSCProfilesManager setOnScreenWidgetViewsSet:self.onScreenWidgetViews]; // pass the keyboard button dict to profiles manager //isToolbarHidden = NO; // keeps track if the toolbar is hidden up above the screen so that we know whether to hide or show it when the user taps the toolbar's hide/show button _quickSwitchEnabled = false; + viewWillBeResized = false; /* add curve to bottom of chevron tab view */ UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.chevronView.bounds byRoundingCorners:(UIRectCornerBottomLeft | UIRectCornerBottomRight) cornerRadii:CGSizeMake(10.0, 10.0)]; @@ -155,8 +166,9 @@ self.layoutOSC = [[LayoutOnScreenControls alloc] initWithView:self.view controllerSup:nil streamConfig:nil oscLevel:OSCSegmentSelected]; self.layoutOSC._level = OnScreenControlsLevelCustom; self.layoutOSC.layoutToolVC = self; + //[self.layoutOSC show]; // draw on screen controls [self.layoutOSC show]; // draw on screen controls - + [self addInnerAnalogSticksToOuterAnalogLayers]; // allows inner and analog sticks to be dragged together around the screen together as one unit which is the expected behavior self.undoButton.alpha = 0.3; // no changes to undo yet, so fade out the undo button a bit @@ -238,12 +250,16 @@ object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(OSCLayoutChanged) name:@"OSCLayoutChanged" object:nil]; // used to notifiy this view controller that the user made a change to the OSC layout so that the VC can either fade in or out its 'Undo button' which will signify to the user whether there are any OSC layout changes to undo - + + [[NSNotificationCenter defaultCenter] addObserver: self + selector: @selector(handleReturnToForeground) + name: UIApplicationDidBecomeActiveNotification + object: nil]; [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(applicationWillResignActive:) - name:UIApplicationWillResignActiveNotification + selector:@selector(deviceOrientationDidChange) // handle orientation change since i made portrait mode available + name:UIDeviceOrientationDidChangeNotification object:nil]; - + OnScreenWidgetView.editMode = true; [self handleMissingToolBarIcon:toolbarRootView]; [self profileRefresh]; @@ -251,10 +267,33 @@ #pragma mark - Class Helper Functions -- (void)applicationWillResignActive:(NSNotification *)notification { - [self saveTapped:nil]; +- (void)handleReturnToForeground { + [OSCProfilesManager setOnScreenWidgetViewsSet:self.onScreenWidgetViews]; // pass the keyboard button dict to profiles manager } +- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id)coordinator{ + viewWillBeResized = true; + [self clearStickIndicator]; + if(!_quickSwitchEnabled) [self saveTapped:nil]; +} + +- (void)deviceOrientationDidChange{ + [self performSelector:@selector(handleOrientationChangeForOnScreenWidgets) withObject:self afterDelay:0.05]; +} + +- (void)handleOrientationChangeForOnScreenWidgets{ + if(!viewWillBeResized) return; + [self setupWidgetPanel]; + + viewWillBeResized = false; + selectedWidgetView = nil; + selectedControllerLayer = nil; + + _oscProfilesTableViewController.layoutViewBounds = self.view.bounds; + [OSCProfilesManager setOnScreenWidgetViewsSet:self.onScreenWidgetViews]; // pass the keyboard button dict to profiles manager + [self reloadOnScreenWidgetViews]; + [self reloadLegacyOnScreenControls]; +} /* fades the 'Undo Button' in or out depending on whether the user has any OSC layout changes to undo */ - (void) OSCLayoutChanged { @@ -379,8 +418,8 @@ UIAlertAction *readInstruction = [UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Read Widget Instruction"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ - [self saveTapped:nil]; - NSURL *url = [NSURL URLWithString:@"https://b23.tv/J8qEXOr"]; + //[self saveTapped:nil]; + NSURL *url = [NSURL URLWithString:[LocalizationHelper localizedStringForKey:@"onScreenWidgetStackDoc"]]; if ([[UIApplication sharedApplication] canOpenURL:url]) { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; } @@ -435,7 +474,8 @@ UIAlertAction *readInstruction = [UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Read Widget Instruction"] style:UIAlertActionStyleDefault handler:^(UIAlertAction *action){ - NSURL *url = [NSURL URLWithString:@"https://b23.tv/J8qEXOr"]; + //[self saveTapped:nil]; + NSURL *url = [NSURL URLWithString:[LocalizationHelper localizedStringForKey:@"onScreenWidgetStackDoc"]]; if ([[UIApplication sharedApplication] canOpenURL:url]) { [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil]; } @@ -503,7 +543,7 @@ textField.spellCheckingType = UITextSpellCheckingTypeNo; textField.text = self->selectedWidgetView.shape; if([self->selectedWidgetView.shape isEqualToString: @"largeSquare"]) textField.enabled = false; - }]; + }]; UIAlertAction *createNewAction = [UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Create New"] @@ -587,10 +627,10 @@ [newWidget resizeWidgetView]; // resize must be called after relocation [newWidget adjustTransparencyWithAlpha:widget.backgroundAlpha]; [newWidget adjustBorderWithWidth:widget.borderWidth]; - [self.OnScreenWidgetViews addObject:newWidget]; + [self.onScreenWidgetViews addObject:newWidget]; self->selectedWidgetView = newWidget; if(!createNew){ - [self.OnScreenWidgetViews removeObject:widget]; + [self.onScreenWidgetViews removeObject:widget]; [widget removeFromSuperview]; } } @@ -603,7 +643,7 @@ widgetView.guidelineDelegate = (id)self; widgetView.translatesAutoresizingMaskIntoConstraints = NO; // weird but this is mandatory, or you will find no key views added to the right place widgetView.minStickOffset = [widgetInitParams[@"minStickOffsetString"] floatValue]; - [self.OnScreenWidgetViews addObject:widgetView]; + [self.onScreenWidgetViews addObject:widgetView]; // Add the widgetView to the view controller's view [self.view insertSubview:widgetView belowSubview:self.widgetPanelStack]; [widgetView setLocationWithPosition:CGPointMake(90, 130)]; @@ -614,6 +654,7 @@ /* show pop up notification that lets users choose to save the current OSC layout configuration as a profile they can load when they want. User can also choose to cancel out of this pop up */ - (IBAction) saveTapped:(id)sender { + [OSCProfilesManager setLayoutViewBounds:self.view.bounds]; if([self->profilesManager updateSelectedProfile:self.layoutOSC.OSCButtonLayers]){ UIAlertController * savedAlertController = [UIAlertController alertControllerWithTitle: [NSString stringWithFormat:@""] message: [LocalizationHelper localizedStringForKey:@"Current profile updated successfully"] preferredStyle:UIAlertControllerStyleAlert]; @@ -1105,12 +1146,9 @@ //this part is just for registration, will not be immediately executed. self->_oscProfilesTableViewController.needToUpdateOscLayoutTVC = ^() { // a block that will be called when the modally presented 'OSCProfilesTableViewController' VC is dismissed. By the time the 'OSCProfilesTableViewController' VC is dismissed the user would have potentially selected a different OSC profile with a different layout and they want to see this layout on this 'LayoutOnScreenControlsViewController.' This block of code will load the profile and then hide/show and move each OSC button to their appropriate position - [self.layoutOSC updateControls]; // creates and saves a 'Default' OSC profile or loads the one the user selected on the previous screen - [self addInnerAnalogSticksToOuterAnalogLayers]; - [self.layoutOSC.layoutChanges removeAllObjects]; // since a new OSC profile is being loaded, this will remove all previous layout changes made from the array - [self OSCLayoutChanged]; // fades the 'Undo Button' out + NSLog(@"profile profile"); + [self reloadLegacyOnScreenControls]; self->_oscProfilesTableViewController.currentOSCButtonLayers = self.layoutOSC.OSCButtonLayers; //pass updated OSCLayout to OSCProfileTableView again - //[self reloadOnScreenKeyboardButtons]; }; [self.oscProfilesTableViewController profileViewRefresh]; // execute this will make sure OSCLayout is updated from persisted profile, not any cache. @@ -1133,16 +1171,10 @@ } _oscProfilesTableViewController = [storyboard instantiateViewControllerWithIdentifier:@"OSCProfilesTableViewController"]; - _oscProfilesTableViewController.streamViewBounds = self.view.bounds; + _oscProfilesTableViewController.layoutViewBounds = self.view.bounds; _oscProfilesTableViewController.needToUpdateOscLayoutTVC = ^() { // a block that will be called when the modally presented 'OSCProfilesTableViewController' VC is dismissed. By the time the 'OSCProfilesTableViewController' VC is dismissed the user would have potentially selected a different OSC ofile with a different layout and they want to see this layout on this 'LayoutOnScreenControlsViewController.' This block of code will load the proffile and then hide/show and move each OSC button to their appropriate position - [self.layoutOSC updateControls]; // creates and saves a 'Default' OSC profile or loads the one the user selected on the previous screen - - [self addInnerAnalogSticksToOuterAnalogLayers]; - - [self.layoutOSC.layoutChanges removeAllObjects]; // since a new OSC profile is being loaded, this will remove all previous layout changes made from the array - - [self OSCLayoutChanged]; // fades the 'Undo Button' out + [self reloadLegacyOnScreenControls]; }; self.widgetPanelStack.hidden = YES; @@ -1252,7 +1284,7 @@ if(!isToolbarHidden && self->selectedWidgetView != nil && [self layerIsOverlappingWithTrashcanButton:selectedWidgetView.layer]){ [self->selectedWidgetView removeFromSuperview]; - [self.OnScreenWidgetViews removeObject:self->selectedWidgetView]; + [self.onScreenWidgetViews removeObject:self->selectedWidgetView]; [self clearStickIndicator]; [selectedWidgetView.buttonDownVisualEffectLayer removeFromSuperlayer]; } diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.h b/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.h index c7a3735e..ebd90c87 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.h +++ b/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.h @@ -30,7 +30,7 @@ typedef NS_ENUM(NSUInteger, FileOperation) { @property (weak, nonatomic) IBOutlet UITableView *tableView; @property (nonatomic, copy) void (^needToUpdateOscLayoutTVC)(void); @property (nonatomic, assign) NSMutableArray *currentOSCButtonLayers; -@property (nonatomic, assign) CGRect streamViewBounds; +@property (nonatomic, assign) CGRect layoutViewBounds; @property (weak, nonatomic) IBOutlet UINavigationBar *profileTableViewNavigationBar; @end diff --git a/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.m b/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.m index cde34b02..06546075 100644 --- a/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.m +++ b/VoidLink/ViewControllers/CustomOSCViewControl/OSCProfilesTableViewController.m @@ -74,7 +74,7 @@ const double NAV_BAR_HEIGHT = 50; // self.profileTableViewNavigationBar.layer.cornerRadius = 15; // 设置圆角半径 - profilesManager = [OSCProfilesManager sharedManager:_streamViewBounds]; + profilesManager = [OSCProfilesManager sharedManager:_layoutViewBounds]; self.tableView.tableHeaderView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 0, NAV_BAR_HEIGHT)]; diff --git a/VoidLink/ViewControllers/MainFrameViewController.h b/VoidLink/ViewControllers/MainFrameViewController.h index ebc9b42e..8d978cd8 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.h +++ b/VoidLink/ViewControllers/MainFrameViewController.h @@ -13,7 +13,6 @@ #import "DiscoveryManager.h" #import "PairManager.h" #import "StreamConfiguration.h" -#import "UIComputerView.h" #import "HostCardView.h" #import "UIAppView.h" #import "AppAssetManager.h" @@ -21,7 +20,7 @@ #import "HostCollectionViewController.h" -@interface MainFrameViewController : UICollectionViewController +@interface MainFrameViewController : UICollectionViewController @property (nonatomic, strong) IBOutlet UIBarButtonItem *settingsButton; #if !TARGET_OS_TV diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index 492fbc67..461af22b 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -16,7 +16,6 @@ #import "Connection.h" #import "StreamManager.h" #import "Utils.h" -#import "UIComputerView.h" #import "UIAppView.h" #import "DataManager.h" #import "TemporarySettings.h" @@ -25,7 +24,6 @@ #import "ServerInfoResponse.h" #import "StreamFrameViewController.h" #import "LoadingFrameViewController.h" -#import "ComputerScrollView.h" #import "TemporaryApp.h" #import "IdManager.h" #import "ConnectionHelper.h" @@ -597,22 +595,24 @@ static NSMutableSet* hostList; Log(LOG_D, @"Long clicked host: %@", host.name); NSString* message; + NSString* hostAddress = [host.activeAddress componentsSeparatedByString:@":"].firstObject; + switch (host.state) { case StateOffline: - message = [LocalizationHelper localizedStringForKey:@"Offline"]; + message = [LocalizationHelper localizedStringForKey:@"Offline\n%@", hostAddress ? hostAddress : @"Unknown address"]; break; case StateOnline: if (host.pairState == PairStatePaired) { - message = [LocalizationHelper localizedStringForKey:@"Online - Paired"]; + message = [LocalizationHelper localizedStringForKey:@"Online - Paired\n%@", hostAddress ? hostAddress : @"Unknown address"]; } else { - message = [LocalizationHelper localizedStringForKey:@"Online - Not Paired"]; + message = [LocalizationHelper localizedStringForKey:@"Online - Not Paired\n%@", hostAddress ? hostAddress : @"Unknown address"]; } break; case StateUnknown: - message = [LocalizationHelper localizedStringForKey:@"Connecting"]; + message = [LocalizationHelper localizedStringForKey:@"Connecting\n"]; break; default: @@ -622,7 +622,7 @@ static NSMutableSet* hostList; UIAlertController* longClickAlert = [UIAlertController alertControllerWithTitle:host.name message:message preferredStyle:UIAlertControllerStyleActionSheet]; if (host.state != StateOnline) { - /*[longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Wake PC"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ + [longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Wake PC"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:[LocalizationHelper localizedStringForKey:@"Wake-On-LAN"] message:@"" preferredStyle:UIAlertControllerStyleAlert]; [wolAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Ok"] style:UIAlertActionStyleDefault handler:nil]]; if (host.mac == nil || [host.mac isEqualToString:@"00:00:00:00:00:00"]) { @@ -634,7 +634,7 @@ static NSMutableSet* hostList; wolAlert.message = [LocalizationHelper localizedStringForKey:@"Successfully sent wake-up request. It may take a few moments for the PC to wake. If it never wakes up, ensure it's properly configured for Wake-on-LAN."]; } [[self activeViewController] presentViewController:wolAlert animated:YES completion:nil]; - }]];*/ + }]]; } else if (host.pairState == PairStatePaired) { /* @@ -644,18 +644,14 @@ static NSMutableSet* hostList; }]]; */ #if !TARGET_OS_TV - if (false) { - [longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"NVIDIA GameStream End-of-Service"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ - [Utils launchUrl:@"https://github.com/moonlight-stream/moonlight-docs/wiki/NVIDIA-GameStream-End-Of-Service-Announcement-FAQ"]; - }]]; - } + #endif } - [longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Test Network"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) { + /*[longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Test Network"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action) { [self showLoadingFrame:^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // Perform the network test on a GCD worker thread. It may take a while. - unsigned int portTestResult = LiTestClientConnectivity(CONN_TEST_SERVER, 443, ML_PORT_FLAG_ALL); + unsigned int portTestResult = LiTestClientConnectivity([host.activeAddress UTF8String], 443, ML_PORT_FLAG_ALL); dispatch_sync(dispatch_get_main_queue(), ^{ [self hideLoadingFrame:^{ NSString* message; @@ -681,8 +677,9 @@ static NSMutableSet* hostList; }); }); }]; - }]]; + }]];*/ #if !TARGET_OS_TV + /* if (host.state != StateOnline) { [longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"NVIDIA GameStream End-of-Service"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ [Utils launchUrl:@"https://github.com/moonlight-stream/moonlight-docs/wiki/NVIDIA-GameStream-End-Of-Service-Announcement-FAQ"]; @@ -690,7 +687,7 @@ static NSMutableSet* hostList; [longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Connection Help"] style:UIAlertActionStyleDefault handler:^(UIAlertAction* action){ [Utils launchUrl:@"https://github.com/moonlight-stream/moonlight-docs/wiki/Troubleshooting"]; }]]; - } + }*/ #endif [longClickAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Remove Host"] style:UIAlertActionStyleDestructive handler:^(UIAlertAction* action) { // host removed here [self->_discMan removeHostFromDiscovery:host]; @@ -748,7 +745,7 @@ static NSMutableSet* hostList; }]; }); } else { - unsigned int portTestResults = LiTestClientConnectivity(CONN_TEST_SERVER, 443, + unsigned int portTestResults = LiTestClientConnectivity([host.activeAddress UTF8String], 443, ML_PORT_FLAG_TCP_47984 | ML_PORT_FLAG_TCP_47989); if (portTestResults != ML_TEST_RESULT_INCONCLUSIVE && portTestResults != 0) { error = [error stringByAppendingString:[LocalizationHelper localizedStringForKey:@"!ML_TEST_RESULT_INCONCLUSIVE"]]; @@ -1144,7 +1141,7 @@ static NSMutableSet* hostList; [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.audioOnPcStack]; [settingsViewController.codecSelector setEnabled:!_settingsExpandedInStreamView]; [settingsViewController.yuv444Switch setEnabled:!_settingsExpandedInStreamView]; - [settingsViewController.hdrSwitch setEnabled:!_settingsExpandedInStreamView]; + [settingsViewController.hdrSwitch setEnabled:!_settingsExpandedInStreamView && [settingsViewController hdrSupported]]; [settingsViewController.gyroModeSelector setEnabled:!_settingsExpandedInStreamView || ![streamFrameViewController shallDisableGyroHotSwitch]]; [settingsViewController.emulatedControllerTypeSelector setEnabled:!_settingsExpandedInStreamView]; [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.framepacingStack]; @@ -1470,7 +1467,7 @@ static NSMutableSet* hostList; if (@available(iOS 13.0, *)) { [_upButton setTitle:@""]; - UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:23 weight:UIImageSymbolWeightMedium ]; + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:21.5 weight:UIImageSymbolWeightMedium ]; UIImage *image = [[UIImage systemImageNamed:@"tv" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [_upButton setImage:image]; _upButton.imageInsets = UIEdgeInsetsMake(25, 20, 0, 15); @@ -1933,7 +1930,7 @@ static NSMutableSet* hostList; [self updateHostShortcuts]; // Update the title in case we now have a PC - [self updateTitle]; + // [self updateTitle]; // Reset state first so we can rediscover hosts that were deleted before [_discMan resetDiscoveryState]; @@ -1942,7 +1939,7 @@ static NSMutableSet* hostList; // This function forces immediate decoding of the UIImage, rather // than the default lazy decoding that results in janky scrolling. -(void)deviceOrientationDidChange{ - if(self.collectionView.superview == nil) return; + if(self.revealViewController.isStreaming || self.collectionView.superview == nil) return; [NSLayoutConstraint activateConstraints:@[ [self.collectionView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], [self.collectionView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], diff --git a/VoidLink/ViewControllers/SettingsViewController.h b/VoidLink/ViewControllers/SettingsViewController.h index 49754f21..a4d3f581 100644 --- a/VoidLink/ViewControllers/SettingsViewController.h +++ b/VoidLink/ViewControllers/SettingsViewController.h @@ -133,6 +133,7 @@ #pragma clang diagnostic pop +- (bool)hdrSupported; - (void)saveSettings; + (bool)isLandscapeNow; - (void)updateResolutionTable; diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index dae84618..73ad1e32 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -287,6 +287,8 @@ BOOL isCustomResolution(CGSize res) { } - (void)updateResolutionTable{ + if(self.mainFrameViewController.settingsExpandedInStreamView) return; + UIWindow *window = self.view.window; NSLog(@" window %@", window); @@ -391,7 +393,7 @@ BOOL isCustomResolution(CGSize res) { _parentStack.translatesAutoresizingMaskIntoConstraints = NO; [self.scrollView addSubview:_parentStack]; [NSLayoutConstraint activateConstraints:@[ - [_parentStack.topAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.topAnchor constant: currentSettingsMenuMode == AllSettings ? [self getStandardNavBarHeight] : [self getStandardNavBarHeight]+20], + [_parentStack.topAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.topAnchor constant: currentSettingsMenuMode == AllSettings ? [self getStandardNavBarHeight] : [self getStandardNavBarHeight]+10], [_parentStack.bottomAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.bottomAnchor constant:-20], [_parentStack.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor constant: 0], //mark: settingMenuLayout [_parentStack.widthAnchor constraintEqualToAnchor:self.view.widthAnchor constant:-20] // section width adjusted here //mark: settingMenuLayout @@ -533,7 +535,7 @@ BOOL isCustomResolution(CGSize res) { touchAndControlSection = [[MenuSectionView alloc] init]; touchAndControlSection.delegate = self; - touchAndControlSection.sectionTitle = [LocalizationHelper localizedStringForKey:@"Touch & Control"]; + touchAndControlSection.sectionTitle = [LocalizationHelper localizedStringForKey:@"Touch & Controller"]; if (@available(iOS 13.0, *)) { [touchAndControlSection setSectionWithIcon:[UIImage imageNamed:@"arcade.stick.console"] andSize:20.5]; } @@ -1172,6 +1174,20 @@ BOOL isCustomResolution(CGSize res) { } } +/* +- (BOOL)isFirstLaunch { + NSString *key = @"appHasLaunchedBefore"; + BOOL launchedBefore = [[NSUserDefaults standardUserDefaults] boolForKey:key]; + + if (!launchedBefore) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:key]; + [[NSUserDefaults standardUserDefaults] synchronize]; // iOS 12+ 可省略 + return YES; + } + return NO; +} +*/ + - (void)saveFavoriteSettingStackIdentifiers { if(currentSettingsMenuMode != AllSettings){ @@ -1181,18 +1197,40 @@ BOOL isCustomResolution(CGSize res) { [_favoriteSettingStackIdentifiers addObject:_parentStack.arrangedSubviews[i].accessibilityIdentifier]; } } - [[NSUserDefaults standardUserDefaults] setObject:_favoriteSettingStackIdentifiers forKey:@"FavoriteSettingStackIdentifiers"]; [[NSUserDefaults standardUserDefaults] synchronize]; } - (void)loadFavoriteSettingStackIdentifiers { NSArray *savedArray = [[NSUserDefaults standardUserDefaults] objectForKey:@"FavoriteSettingStackIdentifiers"]; + if ([savedArray isKindOfClass:[NSArray class]]) { _favoriteSettingStackIdentifiers = [savedArray mutableCopy]; } else { _favoriteSettingStackIdentifiers = [NSMutableArray array]; + [_favoriteSettingStackIdentifiers addObject:@"resolutionStack"]; + [_favoriteSettingStackIdentifiers addObject:@"fpsStack"]; + [_favoriteSettingStackIdentifiers addObject:@"bitrateStack"]; + [_favoriteSettingStackIdentifiers addObject:@"framepacingStack"]; + [_favoriteSettingStackIdentifiers addObject:@"codecStack"]; + [_favoriteSettingStackIdentifiers addObject:@"hdrStack"]; + [_favoriteSettingStackIdentifiers addObject:@"yuv444Stack"]; + [_favoriteSettingStackIdentifiers addObject:@"pipStack"]; + [_favoriteSettingStackIdentifiers addObject:@"touchModeStack"]; + [_favoriteSettingStackIdentifiers addObject:@"pointerVelocityDividerStack"]; + [_favoriteSettingStackIdentifiers addObject:@"pointerVelocityFactorStack"]; + [_favoriteSettingStackIdentifiers addObject:@"mousePointerVelocityStack"]; + [_favoriteSettingStackIdentifiers addObject:@"onScreenWidgetStack"]; + [_favoriteSettingStackIdentifiers addObject:@"pipStack"]; + [_favoriteSettingStackIdentifiers addObject:@"backgroundSessionTimerStack"]; + [_favoriteSettingStackIdentifiers addObject:@"statsOverlayStack"]; + [_favoriteSettingStackIdentifiers addObject:@"softKeyboardGestureStack"]; + [_favoriteSettingStackIdentifiers addObject:@"slideToSettingsScreenEdgeStack"]; + [_favoriteSettingStackIdentifiers addObject:@"slideToToolboxScreenEdgeStack"]; + [_favoriteSettingStackIdentifiers addObject:@"slideToSettingsDistanceStack"]; + [_favoriteSettingStackIdentifiers addObject:@"unlockDisplayOrientationStack"]; } + /* for(NSString* str in _favoriteSettingStackIdentifiers){ NSLog(@"favarite setting loaded: %@", str); @@ -1332,7 +1370,7 @@ BOOL isCustomResolution(CGSize res) { if (![self hdrSupported]) { [self.hdrSwitch setOn:NO]; - [self widget:self.hdrSwitch setEnabled:NO]; + [self.hdrSwitch setEnabled:NO]; } else { [self.hdrSwitch setOn:currentSettings.enableHdr]; @@ -1508,21 +1546,6 @@ BOOL isCustomResolution(CGSize res) { [self.enableOswForNativeTouchSwitch addTarget:self action:@selector(enableOswForNativeTouchSwitchFlipped:) forControlEvents:UIControlEventValueChanged]; [self enableOswForNativeTouchSwitchFlipped:self.enableOswForNativeTouchSwitch]; - - // init CustomOSC stuff - /* sets a reference to the correct 'LayoutOnScreenControlsViewController' depending on whether the user is on an iPhone or iPad */ - // self.layoutOnScreenControlsVC = [[LayoutOnScreenControlsViewController alloc] init]; - BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone); - if (isIPhone) { - UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPhone" bundle:nil]; - self.layoutOnScreenControlsVC = [storyboard instantiateViewControllerWithIdentifier:@"LayoutOnScreenControlsViewController"]; - } - else { - UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPad" bundle:nil]; - self.layoutOnScreenControlsVC = [storyboard instantiateViewControllerWithIdentifier:@"LayoutOnScreenControlsViewController"]; - self.layoutOnScreenControlsVC.modalPresentationStyle = UIModalPresentationFullScreen; - } - [self.externalDisplayModeSelector setSelectedSegmentIndex:currentSettings.externalDisplayMode.integerValue]; [self.localMousePointerModeSelector setSelectedSegmentIndex:currentSettings.localMousePointerMode.integerValue]; @@ -1628,6 +1651,20 @@ BOOL isCustomResolution(CGSize res) { } - (void)invokeOscLayout{ + // init CustomOSC stuff + /* sets a reference to the correct 'LayoutOnScreenControlsViewController' depending on whether the user is on an iPhone or iPad */ + // self.layoutOnScreenControlsVC = [[LayoutOnScreenControlsViewController alloc] init]; + BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone); + if (isIPhone) { + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPhone" bundle:nil]; + self.layoutOnScreenControlsVC = [storyboard instantiateViewControllerWithIdentifier:@"LayoutOnScreenControlsViewController"]; + } + else { + UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPad" bundle:nil]; + self.layoutOnScreenControlsVC = [storyboard instantiateViewControllerWithIdentifier:@"LayoutOnScreenControlsViewController"]; + self.layoutOnScreenControlsVC.modalPresentationStyle = UIModalPresentationFullScreen; + } + self.layoutOnScreenControlsVC.view.backgroundColor = [UIColor colorWithWhite:0.55 alpha:1.0]; [self presentViewController:self.layoutOnScreenControlsVC animated:YES completion:nil]; } diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index f4b818a9..ab3ffeca 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -64,6 +64,7 @@ UIScrollView *_scrollView; BOOL _userIsInteracting; bool viewJustLoaded; + bool viewIsBeingResized; CGSize _keyboardSize; PlotMetrics _decodeMetrics; PlotMetrics _frameDropMetrics; @@ -241,15 +242,8 @@ } - (void)configOscLayoutTool{ + if([self isOscLayoutToolEnabled]){ - _oscLayoutTapRecoginizer = [[CustomTapGestureRecognizer alloc] initWithTarget:self action:@selector(openWidgetLayoutTool)]; - _oscLayoutTapRecoginizer.numberOfTouchesRequired = _settings.oscLayoutToolFingers.intValue; //tap a predefined number of fingers to open osc layout tool - _oscLayoutTapRecoginizer.tapDownTimeThreshold = 0.2; - _oscLayoutTapRecoginizer.delaysTouchesBegan = NO; - _oscLayoutTapRecoginizer.delaysTouchesEnded = NO; - if(_settings.touchMode.intValue == AbsoluteTouch) _oscLayoutTapRecoginizer.immediateTriggering = true; // make immediate triggering on for absolute touch mode - - [self.view addGestureRecognizer:_oscLayoutTapRecoginizer]; // /* sets a reference to the correct 'LayoutOnScreenControlsViewController' depending on whether the user is on an iPhone or iPad */ // _layoutOnScreenControlsVC = [[LayoutOnScreenControlsViewController alloc] init]; BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone); @@ -265,20 +259,22 @@ _layoutOnScreenControlsVC.view.backgroundColor = UIColor.clearColor; _layoutOnScreenControlsVC.modalPresentationStyle = UIModalPresentationOverCurrentContext; } + //NSLog(@"in osc frameview gestures: %d", (uint32_t)[self.view.gestureRecognizers count]); + //NSLog(@"in osc streamview gestures: %d", (uint32_t)[_streamView.gestureRecognizers count]); } - (void)presentToolboxViewController{ + [self configOscLayoutTool]; ToolboxViewController* oldToolboxVC = toolBoxViewController; toolBoxViewController = [[ToolboxViewController alloc] init]; toolBoxViewController.specialEntryDelegate = self; toolBoxViewController.specialEntries = oldToolboxVC.specialEntries; - [self configOscLayoutTool]; [self presentViewController:toolBoxViewController animated:YES completion:^{ //[self->toolBoxViewController setupConstraints]; }]; } -- (void)configSwipeGestures{ +- (void)configGestures{ _slideToSettingsRecognizer = [[CustomEdgeSlideGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)]; _slideToSettingsRecognizer.edges = _settings.slideToSettingsScreenEdge.intValue; _slideToSettingsRecognizer.normalizedThresholdDistance = _settings.slideToSettingsDistance.floatValue; @@ -294,6 +290,17 @@ _slideToCmdToolRecognizer.delaysTouchesBegan = NO; _slideToCmdToolRecognizer.delaysTouchesEnded = NO; [self.view addGestureRecognizer:_slideToCmdToolRecognizer]; + + if([self isOscLayoutToolEnabled]){ + _oscLayoutTapRecoginizer = [[CustomTapGestureRecognizer alloc] initWithTarget:self action:@selector(handleWidgetLayoutGesture)]; + _oscLayoutTapRecoginizer.numberOfTouchesRequired = _settings.oscLayoutToolFingers.intValue; //tap a predefined number of fingers to open osc layout tool + _oscLayoutTapRecoginizer.tapDownTimeThreshold = 0.2; + _oscLayoutTapRecoginizer.delaysTouchesBegan = NO; + _oscLayoutTapRecoginizer.delaysTouchesEnded = NO; + if(_settings.touchMode.intValue == AbsoluteTouch) _oscLayoutTapRecoginizer.immediateTriggering = true; // make immediate triggering on for absolute touch mode + [self.view addGestureRecognizer:_oscLayoutTapRecoginizer]; // + } + } - (void)configZoomGestureAndAddStreamView{ @@ -337,9 +344,10 @@ _settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here. } overlayLevel = _settings.statsOverlayLevel.intValue; - [self configOscLayoutTool]; + if(viewIsBeingResized) viewIsBeingResized = false; + else [self configOscLayoutTool]; [self updateToolboxSpecialEntries]; - [self configSwipeGestures]; + [self configGestures]; [self configZoomGestureAndAddStreamView]; [self->_streamView disableOnScreenControls]; //don't know why but this must be called outside the streamview class, just put it here. execute in streamview class cause hang [self.mainFrameViewcontroller reloadStreamConfig]; // reload streamconfig @@ -542,6 +550,7 @@ - (void)viewDidLoad { viewJustLoaded = true; + viewIsBeingResized = false; [super viewDidLoad]; [self.navigationController setNavigationBarHidden:YES animated:YES]; @@ -699,10 +708,15 @@ [_streamView keyboardWillHide]; } +- (void)handleWidgetLayoutGesture{ + [self configOscLayoutTool]; + [self openWidgetLayoutTool]; +} - (void)openWidgetLayoutTool{ + _streamView.widgetToolOpened = true; [self->_streamView disableOnScreenControls]; - [self->_streamView clearOnScreenKeyboardButtons]; // clear all onScreenKeyboardButtons before entering edit mode + [self->_streamView clearOnScreenWidgets]; // clear all onScreenKeyboardButtons before entering edit mode _layoutOnScreenControlsVC.quickSwitchEnabled = false; _layoutOnScreenControlsVC.toolbarStackView.hidden = false; _layoutOnScreenControlsVC.toolbarRootView.hidden = false; @@ -710,8 +724,9 @@ } - (void)switchWidgetProfile{ + _streamView.widgetToolOpened = true; [self->_streamView disableOnScreenControls]; - [self->_streamView clearOnScreenKeyboardButtons]; // clear all onScreenKeyboardButtons before entering edit mode + [self->_streamView clearOnScreenWidgets]; // clear all onScreenKeyboardButtons before entering edit mode _layoutOnScreenControlsVC.quickSwitchEnabled = true; _layoutOnScreenControlsVC.toolbarStackView.hidden = true; _layoutOnScreenControlsVC.toolbarRootView.hidden = true; @@ -730,6 +745,7 @@ - (void)oscLayoutClosed{ // Handle the callback + _streamView.widgetToolOpened = false; [self->_streamView disableOnScreenControls]; // add this to get realtime back menu working. [self->_streamView reloadOnScreenControlsWith:(ControllerSupport*)_controllerSupport andConfig:(StreamConfiguration*)_streamConfig]; @@ -928,6 +944,7 @@ } - (void) handleViewResize{ + viewIsBeingResized = true; _streamView.bounds = _deviceWindow.bounds; _streamView.frame = _deviceWindow.frame; if(![self isAirPlaying]){