diff --git a/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.h b/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.h index 4e4ef2b0..64233180 100644 --- a/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.h +++ b/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.h @@ -15,6 +15,8 @@ @property (nonatomic, assign) UIRectEdge edges; // Specify the edge(s) you want to recognize the swipe gesture on @property (nonatomic, assign) CGFloat normalizedThresholdDistance; // Distance from the edge to start recognizing the gesture +@property (nonatomic, assign) bool immediateTriggering; +@property (nonatomic, assign) CGFloat edgeTolerancePoints; @end #endif /* CustomEdgeSwipeGestureRecognizer_h */ diff --git a/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.m b/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.m index ee0f51f5..9e9cd431 100644 --- a/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.m +++ b/Limelight/ViewControllers/CustomEdgeSwipeGestureRecognizer.m @@ -13,13 +13,14 @@ @implementation CustomEdgeSwipeGestureRecognizer UITouch* capturedUITouch; -CGFloat _startPointX; +CGFloat startPointX; static CGFloat screenWidthInPoints; -static CGFloat EDGE_TOLERANCE_POINTS = 50.0f; - (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action { self = [super initWithTarget:target action:action]; screenWidthInPoints = CGRectGetWidth([[UIScreen mainScreen] bounds]); // Get the screen's bounds (in points) + _immediateTriggering = false; + _edgeTolerancePoints = 50.0f; return self; } @@ -27,7 +28,23 @@ static CGFloat EDGE_TOLERANCE_POINTS = 50.0f; // [super touchesBegan:touches withEvent:event]; UITouch *touch = [touches anyObject]; capturedUITouch = touch; - _startPointX = [capturedUITouch locationInView:self.view].x; + startPointX = [capturedUITouch locationInView:self.view].x; + if(_immediateTriggering){ + + if(self.edges & UIRectEdgeLeft){ + if(startPointX < _edgeTolerancePoints){ + self.state = UIGestureRecognizerStateEnded; + } + // NSLog(@"startPointX %f , normalizedGestureDeltaX %f", startPointX, normalizedGestureDistance); + } + if(self.edges & UIRectEdgeRight){ + if(startPointX > screenWidthInPoints - _edgeTolerancePoints){ + self.state = UIGestureRecognizerStateEnded; + } + // NSLog(@"startPointX %f , normalizedGestureDeltaX %f", startPointX, normalizedGestureDistance); + } + + } } - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { @@ -35,19 +52,19 @@ static CGFloat EDGE_TOLERANCE_POINTS = 50.0f; if([touches containsObject:capturedUITouch]){ CGFloat _endPointX = [capturedUITouch locationInView:self.view].x; - CGFloat normalizedGestureDistance = fabs(_endPointX - _startPointX)/screenWidthInPoints; + CGFloat normalizedGestureDistance = fabs(_endPointX - startPointX)/screenWidthInPoints; if(self.edges & UIRectEdgeLeft){ - if(_startPointX < EDGE_TOLERANCE_POINTS && normalizedGestureDistance > _normalizedThresholdDistance){ + if(startPointX < _edgeTolerancePoints && normalizedGestureDistance > _normalizedThresholdDistance){ self.state = UIGestureRecognizerStateEnded; } - // NSLog(@"_startPointX %f , normalizedGestureDeltaX %f", _startPointX, normalizedGestureDistance); + // NSLog(@"startPointX %f , normalizedGestureDeltaX %f", startPointX, normalizedGestureDistance); } if(self.edges & UIRectEdgeRight){ - if((_startPointX > (screenWidthInPoints - EDGE_TOLERANCE_POINTS)) && normalizedGestureDistance > _normalizedThresholdDistance){ + if((startPointX > (screenWidthInPoints - _edgeTolerancePoints)) && normalizedGestureDistance > _normalizedThresholdDistance){ self.state = UIGestureRecognizerStateEnded; } - // NSLog(@"_startPointX %f , normalizedGestureDeltaX %f", _startPointX, normalizedGestureDistance); + // NSLog(@"startPointX %f , normalizedGestureDeltaX %f", startPointX, normalizedGestureDistance); } } } diff --git a/Limelight/ViewControllers/MainFrameViewController.h b/Limelight/ViewControllers/MainFrameViewController.h index 5461ec96..b18e6d4a 100644 --- a/Limelight/ViewControllers/MainFrameViewController.h +++ b/Limelight/ViewControllers/MainFrameViewController.h @@ -20,6 +20,8 @@ @property (weak, nonatomic) IBOutlet UIBarButtonItem *settingsButton; #if !TARGET_OS_TV @property (weak, nonatomic) IBOutlet UIBarButtonItem *upButton; + +-(void)simulateSettingsButtonPress; #endif @end diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index ab8606d9..7170eea1 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -27,6 +27,7 @@ #import "IdManager.h" #import "ConnectionHelper.h" #import "LocalizationHelper.h" +#import "CustomEdgeSwipeGestureRecognizer.h" #if !TARGET_OS_TV #import "SettingsViewController.h" @@ -40,6 +41,8 @@ @implementation MainFrameViewController { UILabel* waterMark; + CGFloat recordedScreenWidth; + CustomEdgeSwipeGestureRecognizer* _exitSwipeRecognizer; NSOperationQueue* _opQueue; TemporaryHost* _selectedHost; BOOL _showHiddenApps; @@ -872,17 +875,35 @@ static NSMutableSet* hostList; } #if !TARGET_OS_TV -- (void)simulateSettingsButtonPress { //force expand settings view to update resolution table, and all setting includes current fullscreen resolution will be updated. +- (void)simulateSettingsButtonPressOpen { //force expand settings view to update resolution table, and all setting includes current fullscreen resolution will be updated. if (currentPosition == FrontViewPositionLeft && _settingsButton.target && [_settingsButton.target respondsToSelector:_settingsButton.action]) { [_settingsButton.target performSelector:_settingsButton.action withObject:_settingsButton]; } } +- (void)simulateSettingsButtonPress { //simulate pressing the setting button, called from setting view controller. + if (_settingsButton.target && [_settingsButton.target respondsToSelector:_settingsButton.action]) { + [_settingsButton.target performSelector:_settingsButton.action withObject:_settingsButton]; + } +} + +- (void)handleOrientaionChange { + double delayInSeconds = 0.7; + // Convert the delay into a dispatch_time_t value + dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + // Perform some task after the delay + dispatch_after(delayTime, dispatch_get_main_queue(), ^{// Code to execute after the delay + if(CGRectGetWidth([[UIScreen mainScreen] bounds]) != self->recordedScreenWidth) [self simulateSettingsButtonPressOpen]; //device orientation change condition. + self->recordedScreenWidth = CGRectGetWidth([[UIScreen mainScreen] bounds]); + }); +} - (void)revealController:(SWRevealViewController *)revealController didMoveToPosition:(FrontViewPosition)position { // If we moved back to the center position, we should save the settings + SettingsViewController* settingsViewController = (SettingsViewController*)[revealController rearViewController]; + settingsViewController.mainFrameViewController = self; if (position == FrontViewPositionLeft) { - [(SettingsViewController*)[revealController rearViewController] saveSettings]; + [settingsViewController saveSettings]; _settingsButton.enabled = YES; // make sure these 2 buttons are enabled after closing setting view. _upButton.enabled = YES; // here is the select new host button } @@ -969,6 +990,8 @@ static NSMutableSet* hostList; [self attachWaterMark]; #if !TARGET_OS_TV + + // Set the side bar button action. When it's tapped, it'll show the sidebar. [_settingsButton setTarget:self.revealViewController]; [_settingsButton setAction:@selector(revealToggle:)]; @@ -1049,6 +1072,12 @@ static NSMutableSet* hostList; [self updateTitle]; [self.view addSubview:hostScrollView]; } + + + //if([SettingsViewController isLandscapeNow] != _streamConfig.width > _streamConfig.height) + [self simulateSettingsButtonPress]; //force expand setting view if orientation changed since last quit from app. + [self simulateSettingsButtonPress]; //force expand setting view if orientation changed since last quit from app. + } #if TARGET_OS_TV @@ -1143,11 +1172,12 @@ static NSMutableSet* hostList; #if !TARGET_OS_TV [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(simulateSettingsButtonPress) // //force expand settings view to update resolution table, and all setting includes current fullscreen resolution will be updated. + selector:@selector(handleOrientaionChange) // //force expand settings view to update resolution table, and all setting includes current fullscreen resolution will be updated. name:UIDeviceOrientationDidChangeNotification object:nil]; - + [[self revealViewController] setPrimaryViewController:self]; + recordedScreenWidth = CGRectGetWidth([[UIScreen mainScreen] bounds]); // Get the screen's bounds (in points), for force expand setting view #endif [self.navigationController setNavigationBarHidden:NO animated:YES]; diff --git a/Limelight/ViewControllers/SettingsViewController.h b/Limelight/ViewControllers/SettingsViewController.h index 563eac6e..67366cc7 100644 --- a/Limelight/ViewControllers/SettingsViewController.h +++ b/Limelight/ViewControllers/SettingsViewController.h @@ -9,6 +9,8 @@ #import #import "AppDelegate.h" #import "CustomOSCViewControl/LayoutOnScreenControlsViewController.h" +#import "MainFrameViewController.h" +#import "CustomEdgeSwipeGestureRecognizer.h" @interface SettingsViewController : UIViewController @property (strong, nonatomic) IBOutlet UILabel *bitrateLabel; @@ -44,6 +46,8 @@ @property (strong, nonatomic) IBOutlet UISlider *mousePointerVelocityFactorSlider; @property (strong, nonatomic) IBOutlet UILabel *mousePointerVelocityFactorUILabel; @property (strong, nonatomic) LayoutOnScreenControlsViewController *layoutOnScreenControlsVC; +@property (nonatomic, strong) MainFrameViewController *mainFrameViewController; +@property (nonatomic, strong) CustomEdgeSwipeGestureRecognizer *exitSwipeRecognizer; #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunguarded-availability" @@ -54,5 +58,6 @@ #pragma clang diagnostic pop - (void) saveSettings; ++ (bool) isLandscapeNow; @end diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index 92940447..dc25650c 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -143,7 +143,8 @@ BOOL isCustomResolution(CGSize res) { } for (int i = 0; i < RESOLUTION_TABLE_CUSTOM_INDEX; i++) { - if (res.width == resolutionTable[i].width && res.height == resolutionTable[i].height) { + + if ((res.width == resolutionTable[i].width && res.height == resolutionTable[i].height) || (res.height == resolutionTable[i].width && res.width == resolutionTable[i].height)) { return NO; } } @@ -151,14 +152,27 @@ BOOL isCustomResolution(CGSize res) { return YES; } ++ (bool)isLandscapeNow { + return CGRectGetWidth([[UIScreen mainScreen]bounds]) > CGRectGetHeight([[UIScreen mainScreen]bounds]); +} + - (void)updateResolutionTable{ UIWindow *window = UIApplication.sharedApplication.windows.firstObject; CGFloat screenScale = window.screen.scale; CGFloat safeAreaWidth = (window.frame.size.width - window.safeAreaInsets.left - window.safeAreaInsets.right) * screenScale; CGFloat fullScreenWidth = window.frame.size.width * screenScale; CGFloat fullScreenHeight = window.frame.size.height * screenScale; + resolutionTable[4] = CGSizeMake(safeAreaWidth, fullScreenHeight); resolutionTable[5] = CGSizeMake(fullScreenWidth, fullScreenHeight); + + for(uint8_t i=0;i<7;i++){ + CGFloat longSideLen = resolutionTable[i].height > resolutionTable[i].width ? resolutionTable[i].height : resolutionTable[i].width; + CGFloat shortSideLen = resolutionTable[i].height < resolutionTable[i].width ? resolutionTable[i].height : resolutionTable[i].width; + if([SettingsViewController isLandscapeNow]) resolutionTable[i] = CGSizeMake(longSideLen, shortSideLen); + else resolutionTable[i] = CGSizeMake(shortSideLen, longSideLen); + } + [self updateResolutionDisplayViewText]; } @@ -179,12 +193,27 @@ BOOL isCustomResolution(CGSize res) { }); } +- (void)simulateSettingsButtonPress{ + [self.mainFrameViewController simulateSettingsButtonPress]; +} + + - (void)viewDidLoad { [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange) // handle orientation change since i made portrait mode available name:UIDeviceOrientationDidChangeNotification object:nil]; - + + // for iphones that can not reach mainFrame, to register a gesture to simuluate setting button press & exit from setting view. + _exitSwipeRecognizer = [[CustomEdgeSwipeGestureRecognizer alloc] initWithTarget:self action:@selector(simulateSettingsButtonPress)]; + _exitSwipeRecognizer.edges = UIRectEdgeLeft | UIRectEdgeRight; + _exitSwipeRecognizer.normalizedThresholdDistance = 0; + _exitSwipeRecognizer.edgeTolerancePoints = 5; + _exitSwipeRecognizer.immediateTriggering = true; + _exitSwipeRecognizer.delaysTouchesBegan = NO; + _exitSwipeRecognizer.delaysTouchesEnded = NO; + [self.view addGestureRecognizer:_exitSwipeRecognizer]; + // Always run settings in dark mode because we want the light fonts if (@available(iOS 13.0, tvOS 13.0, *)) { self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; @@ -215,6 +244,7 @@ BOOL isCustomResolution(CGSize res) { resolutionTable[4] = CGSizeMake(safeAreaWidth, fullScreenHeight); resolutionTable[5] = CGSizeMake(fullScreenWidth, fullScreenHeight); resolutionTable[6] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value + [self updateResolutionTable]; // Don't populate the custom entry unless we have a custom resolution if (!isCustomResolution(resolutionTable[6])) { @@ -237,12 +267,11 @@ BOOL isCustomResolution(CGSize res) { NSInteger resolution = 1; for (int i = 0; i < RESOLUTION_TABLE_SIZE; i++) { - if ((int) resolutionTable[i].height == [currentSettings.height intValue] - && (int) resolutionTable[i].width == [currentSettings.width intValue]) { + if (((int) resolutionTable[i].height == [currentSettings.height intValue] && (int) resolutionTable[i].width == [currentSettings.width intValue]) || ((int) resolutionTable[i].width == [currentSettings.height intValue] && (int) resolutionTable[i].height == [currentSettings.width intValue])){ resolution = i; break; } - } + } // Only show the 120 FPS option if we have a > 60-ish Hz display bool enable120Fps = false; @@ -425,6 +454,7 @@ BOOL isCustomResolution(CGSize res) { - (void)onscreenControlChanged{ + BOOL isIPhone = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone); if (isIPhone) { UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"iPhone" bundle:nil];