From 1737eae39b63e1856165747358ea1d9eea36aa1d Mon Sep 17 00:00:00 2001 From: TrueZhuangjia Date: Sun, 15 Jun 2025 23:01:22 +0800 Subject: [PATCH] old iOS compatibility fixes: - strong settingButton reference - hidden stackView heightContraint - navBarAppearance --- Limelight/Base.lproj/iPad.storyboard | 23 +- Limelight/MenuSectionView.h | 6 +- Limelight/MenuSectionView.m | 11 + .../ViewControllers/MainFrameViewController.h | 2 +- .../ViewControllers/MainFrameViewController.m | 110 +-- .../ViewControllers/SWRevealViewController.m | 25 +- .../ViewControllers/SettingsViewController.h | 26 +- .../ViewControllers/SettingsViewController.m | 624 ++++++++++-------- .../ToolBoxViewController.swift | 10 +- 9 files changed, 454 insertions(+), 383 deletions(-) diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard index 5658d452..0df3b82d 100644 --- a/Limelight/Base.lproj/iPad.storyboard +++ b/Limelight/Base.lproj/iPad.storyboard @@ -1,8 +1,8 @@ - + - + @@ -12,7 +12,7 @@ - + @@ -63,8 +63,8 @@ - - + + - + @@ -88,7 +88,7 @@ - + + @@ -876,7 +877,7 @@ - + @@ -898,7 +899,7 @@ - + @@ -937,7 +938,7 @@ - + @@ -959,7 +960,7 @@ - + diff --git a/Limelight/MenuSectionView.h b/Limelight/MenuSectionView.h index ff7ce6a3..9e1ddee1 100644 --- a/Limelight/MenuSectionView.h +++ b/Limelight/MenuSectionView.h @@ -9,9 +9,11 @@ // MenuSectionView.h #import +#import "DataManager.h" -@protocol HideOverlappedDynamicLabelDelegate +@protocol MenuSectionDelegate - (void)hideOverlappedDynamicLabels; +- (SettingsMenuMode)getSettingsMenuMode; @end @@ -27,7 +29,7 @@ @property (nonatomic, assign) CGFloat headerViewHeight; @property (nonatomic, assign) CGFloat headerViewVerticalSpacing; @property (nonatomic, strong) NSMutableArray *subStackViews; -@property (nonatomic, weak) id delegate; // Delegate property +@property (nonatomic, weak) id delegate; // Delegate property // 方法 - (void)setSectionWithIcon:(UIImage *)icon andSize:(CGFloat)size; diff --git a/Limelight/MenuSectionView.m b/Limelight/MenuSectionView.m index d4a229e8..e9c1efad 100644 --- a/Limelight/MenuSectionView.m +++ b/Limelight/MenuSectionView.m @@ -309,12 +309,23 @@ [self updateViewForFoldState]; } +- (SettingsMenuMode)getSettingsMenuMode { + if ([self.delegate respondsToSelector:@selector(getSettingsMenuMode)]) { + return [self.delegate getSettingsMenuMode]; + } else return AllSettings; +} + + - (void)updateViewForFoldState { + if([self getSettingsMenuMode] != AllSettings) return; + [self setNeedsLayout]; + [self layoutIfNeeded]; [self setupConstraints]; if (_expanded) { _rootStackView.hidden = NO; _separatorLine.hidden = NO; CGSize fittingSize = [self.rootStackView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + //CGSize fittingSize = [self.rootStackView systemLayoutSizeFittingSize:UILayoutFittingExpandedSize]; CGFloat rootStackViewHeight = fittingSize.height; fittingSize = [self.headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; CGFloat headerHeight = fittingSize.height; diff --git a/Limelight/ViewControllers/MainFrameViewController.h b/Limelight/ViewControllers/MainFrameViewController.h index ad850215..2f0d501e 100644 --- a/Limelight/ViewControllers/MainFrameViewController.h +++ b/Limelight/ViewControllers/MainFrameViewController.h @@ -23,7 +23,7 @@ @interface MainFrameViewController : UICollectionViewController -@property (weak, nonatomic) IBOutlet UIBarButtonItem *settingsButton; +@property (nonatomic, strong) IBOutlet UIBarButtonItem *settingsButton; #if !TARGET_OS_TV @property (nonatomic, assign) bool settingsExpandedInStreamView; @property (nonatomic, strong) HostCollectionViewController *hostCollectionVC; diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index c3c94a3b..51d920e0 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -70,11 +70,8 @@ bool _background; UIView* menuSeparator; UIView* snapshot; - SettingsViewController* settingsViewController; - - UINavigationBarAppearance *navBarAppearanceStandard; - UINavigationBarAppearance *navBarAppearanceScroll; + id navBarAppearanceStandard; #if TARGET_OS_TV UITapGestureRecognizer* _menuRecognizer; @@ -142,10 +139,11 @@ static NSMutableSet* hostList; - (void)updateTitle { if (@available(iOS 13.0, *)) { - navBarAppearanceScroll.titleTextAttributes = navBarAppearanceStandard.titleTextAttributes = @{ + NSDictionary* titleTextAttributes = @{ NSFontAttributeName: [UIFont systemFontOfSize:20 weight:UIFontWeightMedium], NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 }; + [navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; } if (_selectedHost != nil) { @@ -157,10 +155,11 @@ static NSMutableSet* hostList; } else { if (@available(iOS 13.0, *)) { - navBarAppearanceScroll.titleTextAttributes = navBarAppearanceStandard.titleTextAttributes = @{ + NSDictionary* titleTextAttributes = @{ NSFontAttributeName: [UIFont systemFontOfSize:24 weight:UIFontWeightSemibold], NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 }; + [navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; } /* self.navigationController.navigationBar.titleTextAttributes = @{ @@ -170,11 +169,7 @@ static NSMutableSet* hostList; self.title = [LocalizationHelper localizedStringForKey: @"Hosts" ]; //self.title = nil; } - if (@available(iOS 13.0, *)) { - [self applyNavBarAppearance]; - } else { - self.navigationController.navigationBar.backgroundColor = [ThemeManager appBackgroundColor]; - } + [self applyNavBarAppearance]; } - (void)alreadyPaired { @@ -1121,18 +1116,38 @@ static NSMutableSet* hostList; else [revealController buttonsNotInStreaming]; //[settingsViewController.resolutionSelector setEnabled:!self.settingsExpandedInStreamView]; - settingsViewController.resolutionStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.fpsStack.hidden = self.settingsExpandedInStreamView; + //settingsViewController.resolutionStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.resolutionStack]; + //settingsViewController.fpsStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.fpsStack]; + [settingsViewController widget:settingsViewController.bitrateSlider setEnabled:!self.settingsExpandedInStreamView]; //settingsViewController.bitrateStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.optimizeGamesStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.audioOnPcStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.codecStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.yuv444Stack.hidden = self.settingsExpandedInStreamView; - settingsViewController.HdrStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.framepacingStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.citrixX1MouseStack.hidden = self.settingsExpandedInStreamView; - settingsViewController.externalDisplayModeStack.hidden = self.settingsExpandedInStreamView; + //settingsViewController.optimizeGamesStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.optimizeGamesStack]; + + //settingsViewController.audioOnPcStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.audioOnPcStack]; + + //settingsViewController.codecStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.codecStack]; + + + //settingsViewController.yuv444Stack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.yuv444Stack]; + + //settingsViewController.HdrStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.HdrStack]; + + //settingsViewController.framepacingStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.framepacingStack]; + + //settingsViewController.citrixX1MouseStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.citrixX1MouseStack]; + + //settingsViewController.externalDisplayModeStack.hidden = self.settingsExpandedInStreamView; + [settingsViewController setHidden:_settingsExpandedInStreamView forStack:settingsViewController.externalDisplayModeStack]; + // [settingsViewController.unlockDisplayOrientationSelector setEnabled:!self.settingsExpandedInStreamView && [self isFullScreenRequired]];//need "requires fullscreen" enabled in the app bunddle to make runtime orientation limitation woring } @@ -1368,42 +1383,37 @@ static NSMutableSet* hostList; ]]; } -- (void)applyNavBarAppearance API_AVAILABLE(ios(13.0)){ - self.navigationController.navigationBar.standardAppearance = navBarAppearanceStandard; - self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearanceStandard; +- (void)applyNavBarAppearance{ + if (@available(iOS 13.0, *)) { + self.navigationController.navigationBar.standardAppearance.backgroundColor = [UIColor clearColor]; // old ios depend on this, do not remove + self.navigationController.navigationBar.standardAppearance = navBarAppearanceStandard; + self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearanceStandard; + } + else{ + self.navigationController.navigationBar.backgroundColor = [UIColor clearColor]; // old ios depend on this, do not remove + self.navigationController.navigationBar.barTintColor = [UIColor clearColor]; // ios 14 depend on this, do not remove + self.navigationController.navigationBar.barTintColor = [ThemeManager appBackgroundColor]; // ios 14 depend on this, do not remove + } } - (void)setupNavBar{ if (@available(iOS 13.0, *)) { - navBarAppearanceStandard = [[UINavigationBarAppearance alloc] init]; - [navBarAppearanceStandard configureWithOpaqueBackground]; // 不透明 - navBarAppearanceStandard.backgroundColor =[ThemeManager appBackgroundColor];; // 设置你需要的背景色 - navBarAppearanceStandard.shadowColor = nil; // 去掉底部分割线(可选) - navBarAppearanceStandard.titleTextAttributes = @{ + Class appearanceClass = NSClassFromString(@"UINavigationBarAppearance"); + navBarAppearanceStandard = [[appearanceClass alloc] init]; + [navBarAppearanceStandard performSelector:@selector(configureWithOpaqueBackground)]; // 不透明 + [navBarAppearanceStandard setValue:[ThemeManager appBackgroundColor] forKey:@"backgroundColor"]; // 设置你需要的背景色 + [navBarAppearanceStandard setValue:nil forKey:@"shadowColor"]; // 设置你需要的背景色 + NSDictionary* titleTextAttributes = @{ NSForegroundColorAttributeName: [ThemeManager textColor] }; - navBarAppearanceStandard.shadowColor = [UIColor clearColor]; - navBarAppearanceStandard.backgroundImage = nil; - - /* - navBarAppearanceScroll = [[UINavigationBarAppearance alloc] init]; - [navBarAppearanceScroll configureWithTransparentBackground]; - navBarAppearanceScroll.backgroundEffect = [UIBlurEffect effectWithStyle:UIBlurEffectStyleRegular]; - navBarAppearanceScroll.backgroundColor =[[ThemeManager appBackgroundColor] colorWithAlphaComponent:0.6]; // 设置你需要的背景色 - //navBarAppearanceScroll.shadowColor = nil; // 去掉底部分割线(可选) - navBarAppearanceScroll.titleTextAttributes = @{ - NSForegroundColorAttributeName: [ThemeManager textColor] - }; - // navBarAppearanceScroll.shadowColor = [UIColor clearColor]; - navBarAppearanceScroll.backgroundImage = nil;*/ + [navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; + [navBarAppearanceStandard setValue:[UIColor clearColor] forKey:@"shadowColor"]; + [navBarAppearanceStandard setValue:nil forKey:@"backgroundImage"]; - //appearance. - [self applyNavBarAppearance]; + //navBarAppearanceStandard.backgroundImage = nil; } - else { - self.navigationController.navigationBar.backgroundColor = [ThemeManager appBackgroundColor]; - } - + [self applyNavBarAppearance]; + self->_addHostButton = [self createAddHostButton]; self->_helpButton = [self createHelpButton]; //[self setupHostViewTitle]; @@ -1419,7 +1429,7 @@ static NSMutableSet* hostList; if (@available(iOS 13.0, *)) { [_settingsButton setTitle:nil]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:23 weight:UIImageSymbolWeightMedium ]; - UIImage *image = [[UIImage systemImageNamed:@"sidebar.left" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + UIImage *image = [[UIImage systemImageNamed:@"sidebar.left" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [_settingsButton setImage:image]; _settingsButton.imageInsets = UIEdgeInsetsMake(10, 10, 0, 0); } else { diff --git a/Limelight/ViewControllers/SWRevealViewController.m b/Limelight/ViewControllers/SWRevealViewController.m index c908695a..2b7f5b3d 100755 --- a/Limelight/ViewControllers/SWRevealViewController.m +++ b/Limelight/ViewControllers/SWRevealViewController.m @@ -871,8 +871,6 @@ const int FrontViewPositionNone = 0xff; #pragma mark - Public methods and property accessors - (void)willMoveToPosition{ - - SettingsMenuMode currentMenuMode = [self getSettingsMenuMode]; _separatorLine.hidden = _frontViewPosition == FrontViewPositionLeft; @@ -883,9 +881,9 @@ const int FrontViewPositionNone = 0xff; if(_frontViewPosition != FrontViewPositionLeft){ [self setupMoreButtonMenu]; - [self layoutSettingsView]; - //if(currentMenuMode == AllSettings) [self allSettingSelected]; - //if(currentMenuMode == FavoriteSettings) [self favoriteSettingSelected]; + [self layoutSettingsView]; //注意, 该方法在菜单展开前又运行了一次, 会执行按清单隐藏stack的任务,此时直接使用.hidden = false 的方式,将stack从hiddenstacks清单中移除,导致stack保持隐藏无法恢复; + //而此willMoveToPosition内部方法,发生在 delegate的willMoveToPosition之后(由mainFrameVC执行的委托) + //因此应在mainFrameVC中的willMoveToPosition委托方法中先行setHidden:false,更新hiddenStack清单, 再在此内部方法中运行layoutSettingsView,确保因串流中展开而隐藏的stack可以正确恢复 } else{ // _rearViewRevealWidth = _rearViewRevealWidth + 20; @@ -943,7 +941,8 @@ const int FrontViewPositionNone = 0xff; _dockedNavBar.scrollEdgeAppearance = navBarAppearanceStandard; } else { _dockedNavBar.backgroundColor = [UIColor clearColor]; - _dockedNavBar.barTintColor = [[ThemeManager appBackgroundColor] colorWithAlphaComponent:0.1]; + _dockedNavBar.backgroundColor = [ThemeManager appBackgroundColor]; + _dockedNavBar.shadowImage = [UIImage new]; // remove bottom line for navbar } @@ -983,7 +982,7 @@ const int FrontViewPositionNone = 0xff; if (@available(iOS 13.0, *)) { [backButton setTitle:nil]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:23 weight:UIImageSymbolWeightMedium ]; - UIImage *image = [[UIImage systemImageNamed:@"sidebar.left" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + UIImage *image = [[UIImage systemImageNamed:@"sidebar.left" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [backButton setImage:image]; backButton.imageInsets = UIEdgeInsetsMake(20, 10, 0, 0); } else { @@ -1024,7 +1023,7 @@ const int FrontViewPositionNone = 0xff; if (@available(iOS 13.0, *)) { [_moreButton setTitle:nil]; UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:23 weight:UIImageSymbolWeightMedium ]; - UIImage *image = [[UIImage systemImageNamed:@"ellipsis.circle" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal]; + UIImage *image = [[UIImage systemImageNamed:@"ellipsis.circle" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; [_moreButton setImage:image]; _moreButton.imageInsets = UIEdgeInsetsMake(20, 0, 0, -10); } else { @@ -1198,10 +1197,16 @@ const int FrontViewPositionNone = 0xff; } - (void)disconnectRemoteSession{ + //先不要运行foldRearView, 以确保在断开时可以捕获 hiddenStacks (在串流中展开时已被设置了setHidden),执行临时hidden = false,并重新计算heightContraint, 因此可确保substacks发生转移前恢复原有高度。以下切换all/favorite的方法内置了layoutSettingsView方法,该方法会在新的superView根据额外维护的清单隐藏stack,从而避免stack以hidden状态发生superView转移。 if([self getSettingsMenuMode] == RemoveSettingItem) [self doneRemoveSettingItemSelected]; - - [[NSNotificationCenter defaultCenter] postNotificationName:@"SessionDisconnectedBySettingsMenuNotification" object:self]; + if([self getSettingsMenuMode] == AllSettings) [self allSettingSelected]; + if([self getSettingsMenuMode] == FavoriteSettings) [self favoriteSettingSelected]; + + // foldRearView此时, 收起时先通过mainFrame委托方法触发setHidden:false(hidden=false, 并更新清单) 再由内部willMoveToPosition运行layoutSettingsView,根据清单执行隐藏, 确保经过setHidden:false的stack可以恢复显示。 [self foldRearView]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"SessionDisconnectedBySettingsMenuNotification" object:self]; + + // 以上两段没有执行顺序要求,因为第一段放后面的话, 也能保证stack不会在hidden状态下被转移到新的superView } -(void)deviceOrientationDidChange{ diff --git a/Limelight/ViewControllers/SettingsViewController.h b/Limelight/ViewControllers/SettingsViewController.h index 5d5bf641..89985471 100644 --- a/Limelight/ViewControllers/SettingsViewController.h +++ b/Limelight/ViewControllers/SettingsViewController.h @@ -16,42 +16,42 @@ #import "CustomEdgeSlideGestureRecognizer.h" #import "MenuSectionView.h" -@interface SettingsViewController : UIViewController +@interface SettingsViewController : UIViewController @property (strong, nonatomic) IBOutlet UINavigationBar *navigationBar; @property (strong, nonatomic) UIStackView *parentStack; @property (strong, nonatomic) IBOutlet UIStackView *resolutionStack; @property (strong, nonatomic) IBOutlet UIStackView *fpsStack; @property (strong, nonatomic) IBOutlet UIStackView *bitrateStack; @property (strong, nonatomic) IBOutlet UIStackView *touchModeStack; -@property (weak, nonatomic) IBOutlet UIStackView *enableOswSwitchStack; +@property (strong, nonatomic) IBOutlet UIStackView *enableOswSwitchStack; //@property (strong, nonatomic) IBOutlet UIStackView *asyncTouchStack; -@property (weak, nonatomic) IBOutlet UISwitch *optimizeGamesSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *optimizeGamesSwitch; @property (strong, nonatomic) IBOutlet UIStackView *pointerVelocityDividerStack; @property (strong, nonatomic) IBOutlet UIStackView *pointerVelocityFactorStack; @property (strong, nonatomic) IBOutlet UIStackView *touchMoveEventIntervalStack; @property (strong, nonatomic) IBOutlet UIStackView *mousePointerVelocityStack; @property (strong, nonatomic) IBOutlet UIStackView *onScreenWidgetStack; @property (strong, nonatomic) IBOutlet UIStackView *softKeyboardGestureStack; -@property (weak, nonatomic) IBOutlet UISegmentedControl *softKeyboardGestureSelector; +@property (strong, nonatomic) IBOutlet UISegmentedControl *softKeyboardGestureSelector; @property (strong, nonatomic) IBOutlet UIStackView *liftStreamViewForKeyboardStack; @property (strong, nonatomic) IBOutlet UIStackView *softKeyboardToolbarStack; -@property (weak, nonatomic) IBOutlet UISwitch *softKeyboardToolbarSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *softKeyboardToolbarSwitch; @property (strong, nonatomic) IBOutlet UIStackView *slideToSettingsScreenEdgeStack; @property (strong, nonatomic) IBOutlet UIStackView *slideToToolboxScreenEdgeStack; @property (strong, nonatomic) IBOutlet UIStackView *slideToSettingsDistanceStack; @property (strong, nonatomic) IBOutlet UIStackView *optimizeGamesStack; @property (strong, nonatomic) IBOutlet UIStackView *multiControllerStack; -@property (weak, nonatomic) IBOutlet UISwitch *multiControllerSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *multiControllerSwitch; @property (strong, nonatomic) IBOutlet UIStackView *swapAbaxyStack; @property (strong, nonatomic) IBOutlet UIStackView *audioOnPcStack; -@property (weak, nonatomic) IBOutlet UISwitch *audioOnPcSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *audioOnPcSwitch; @property (strong, nonatomic) IBOutlet UIStackView *codecStack; @property (strong, nonatomic) IBOutlet UIStackView *yuv444Stack; @property (strong, nonatomic) IBOutlet UIStackView *HdrStack; @property (strong, nonatomic) IBOutlet UIStackView *framepacingStack; @property (strong, nonatomic) IBOutlet UIStackView *reverseMouseWheelDirectionStack; @property (strong, nonatomic) IBOutlet UIStackView *citrixX1MouseStack; -@property (weak, nonatomic) IBOutlet UISwitch *citrixX1MouseSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *citrixX1MouseSwitch; @property (strong, nonatomic) IBOutlet UIStackView *statsOverlayStack; @property (strong, nonatomic) IBOutlet UIStackView *unlockDisplayOrientationStack; @property (strong, nonatomic) IBOutlet UIStackView *externalDisplayModeStack; @@ -61,17 +61,17 @@ @property (strong, nonatomic) IBOutlet UISlider *bitrateSlider; @property (strong, nonatomic) IBOutlet UISegmentedControl *framerateSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *resolutionSelector; -@property (weak, nonatomic) IBOutlet UISwitch *customResolutionSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *customResolutionSwitch; @property (strong, nonatomic) IBOutlet UILabel *touchModeLabel; @property (strong, nonatomic) IBOutlet UISegmentedControl *touchModeSelector; -@property (weak, nonatomic) IBOutlet UISwitch *enableOswForNativeTouchSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *enableOswForNativeTouchSwitch; @property (strong, nonatomic) IBOutlet UILabel *onscreenControllerLabel; @property (strong, nonatomic) IBOutlet UISegmentedControl *onScreenWidgetSelector; //@property (strong, nonatomic) IBOutlet UISegmentedControl *asyncNativeTouchPrioritySelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *swapABXYButtonsSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *codecSelector; -@property (weak, nonatomic) IBOutlet UISwitch *hdrSwitch; -@property (weak, nonatomic) IBOutlet UISwitch *yuv444Switch; +@property (strong, nonatomic) IBOutlet UISwitch *hdrSwitch; +@property (strong, nonatomic) IBOutlet UISwitch *yuv444Switch; @property (strong, nonatomic) IBOutlet UISegmentedControl *framePacingSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *reverseMouseWheelDirectionSelector; @property (strong, nonatomic) IBOutlet UISegmentedControl *statsOverlaySelector; @@ -112,6 +112,6 @@ - (void)widget:(UISlider*)widget setEnabled:(bool)enabled; - (void)updateTheme; - (void)hideDynamicLabelsWhenOverlapped:(UIView* )view; - +- (void)setHidden:(BOOL)hidden forStack:(UIStackView* )stack; @end diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index 8c2988d0..afea5c55 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -36,6 +36,7 @@ CGFloat _scrollSpeed; CGFloat _currentRefreshRate; MenuSectionView *touchControlSection; + NSMutableSet* hiddenStacks; } @dynamic overrideUserInterfaceStyle; @@ -1024,17 +1025,39 @@ BOOL isCustomResolution(CGSize res) { } - (void)layoutSettingsView{ - [self.view layoutSubviews]; + [self.scrollView layoutSubviews]; + + //switchToAll/Favorite 调用此方法时,这些hiddenStack已身处新的superView中, 可以正常执行hidden = YES + for(UIStackView* stack in hiddenStacks) stack.hidden = YES; + if(currentSettingsMenuMode == AllSettings){ for(MenuSectionView* section in _parentStack.arrangedSubviews) [section updateViewForFoldState]; } [self hideDynamicLabelsWhenOverlapped:self.parentStack]; } -- (void)switchToFavoriteSettings{ - for(UIView* view in _parentStack.subviews){ - [view removeFromSuperview]; +// 旧版本iOS兼容必要 +- (void)forceRestoreHeightTemporarilyForSettingStackParentView{ + for(UIStackView* stack in hiddenStacks) stack.hidden = NO; + if(currentSettingsMenuMode == AllSettings){ + for(UIView* view in _parentStack.arrangedSubviews){ + if([view isKindOfClass:[MenuSectionView class]]){ + MenuSectionView* section = (MenuSectionView* )view; + [section updateViewForFoldState]; + } + } } + else{ + NSLayoutConstraint* heightConstraint = [_parentStack.heightAnchor constraintEqualToConstant:666]; + heightConstraint.active = YES; + CGSize fittingSize = [_parentStack systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + heightConstraint.constant = fittingSize.height; + } +} + +- (void)switchToFavoriteSettings{ + [self forceRestoreHeightTemporarilyForSettingStackParentView]; + [_parentStack removeFromSuperview]; currentSettingsMenuMode = FavoriteSettings; [self initParentStack]; [self updateTheme]; @@ -1050,13 +1073,13 @@ BOOL isCustomResolution(CGSize res) { [_parentStack addArrangedSubview:_settingStackDict[settingIdentifier]]; } [self hideDynamicLabelsWhenOverlapped:self.parentStack]; + [self layoutSettingsView]; } - (void)switchToAllSettings{ + [self forceRestoreHeightTemporarilyForSettingStackParentView]; currentSettingsMenuMode = AllSettings; - for(UIView* view in _parentStack.subviews){ - [view removeFromSuperview]; - } + [_parentStack removeFromSuperview]; [self initParentStack]; [self layoutSections]; [self updateTheme]; @@ -1065,7 +1088,7 @@ BOOL isCustomResolution(CGSize res) { Settings *currentSettings = [dataMan retrieveSettings]; currentSettings.settingsMenuMode = [NSNumber numberWithInteger:currentSettingsMenuMode]; [dataMan saveData]; - + [self layoutSettingsView]; } - (void)enterRemoveSettingItemMode{ @@ -1122,291 +1145,292 @@ BOOL isCustomResolution(CGSize res) { - (void)viewDidLoad { //[self updateTheme]; - settingStackWillBeRelocatedToLowestPosition = false; - - [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"_UIConstraintBasedLayoutLogUnsatisfiable"]; - - UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; - [self.view addGestureRecognizer:longPress]; - - _settingStackDict = [[NSMutableDictionary alloc] init]; - - // return; - BOOL isIPad = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad); - if(isIPad){ - //[self layoutWidgetes]; // layout for ipad tmply - // [self.view ] - for(UIView* view in self.view.subviews){ - [view removeFromSuperview]; - } - [self initParentStack]; - [self layoutSections]; - } - - - // [self swi]; - - self->slideToCloseSettingsViewRecognizer = [[CustomEdgeSlideGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)]; - slideToCloseSettingsViewRecognizer.edges = UIRectEdgeLeft; - slideToCloseSettingsViewRecognizer.normalizedThresholdDistance = 0.0; - slideToCloseSettingsViewRecognizer.EDGE_TOLERANCE = 10; - slideToCloseSettingsViewRecognizer.immediateTriggering = true; - slideToCloseSettingsViewRecognizer.delaysTouchesBegan = NO; - slideToCloseSettingsViewRecognizer.delaysTouchesEnded = NO; - [self.view addGestureRecognizer:slideToCloseSettingsViewRecognizer]; - - justEnteredSettingsViewDoNotOpenOscLayoutTool = true; - [[NSNotificationCenter defaultCenter] addObserver:self - selector:@selector(deviceOrientationDidChange) // handle orientation change since i made portrait mode available - name:UIDeviceOrientationDidChangeNotification - object:nil]; - - // Always run settings in dark mode because we want the light fonts - if (@available(iOS 13.0, tvOS 13.0, *)) { - self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; - } - - DataManager* dataMan = [[DataManager alloc] init]; - TemporarySettings* currentSettings = [dataMan getSettings]; - - currentSettingsMenuMode = currentSettings.settingsMenuMode.intValue; - [self loadFavoriteSettingStackIdentifiers]; - if(currentSettings.settingsMenuMode.intValue == FavoriteSettings) [self switchToFavoriteSettings]; - /* - switch (currentSettingsMenuMode) { - case FavoriteSettings: - [self switchToFavoriteSettings]; - break; - case AllSettings: - //[self switchToAllSettings]; - break; - default: - break; - } - */ - - - // Ensure we pick a bitrate that falls exactly onto a slider notch - _bitrate = bitrateTable[[self getSliderValueForBitrate:[currentSettings.bitrate intValue]]]; - - // Get the size of the screen with and without safe area insets - 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; - - [self.resolutionSelector removeSegmentAtIndex:0 animated:NO]; // remove 360p - [self.resolutionSelector removeSegmentAtIndex:5 animated:NO]; // remove custom segment + settingStackWillBeRelocatedToLowestPosition = false; + hiddenStacks = [[NSMutableSet alloc] init]; - resolutionTable[0] = CGSizeMake(1280, 720); - resolutionTable[1] = CGSizeMake(1920, 1080); - resolutionTable[2] = CGSizeMake(3840, 2160); - resolutionTable[3] = CGSizeMake(safeAreaWidth, fullScreenHeight); - resolutionTable[4] = CGSizeMake(fullScreenWidth, fullScreenHeight); - resolutionTable[5] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value - [self updateResolutionTable]; + [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"_UIConstraintBasedLayoutLogUnsatisfiable"]; + + UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; + [self.view addGestureRecognizer:longPress]; + + _settingStackDict = [[NSMutableDictionary alloc] init]; + + // return; + BOOL isIPad = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad); + if(isIPad){ + //[self layoutWidgetes]; // layout for ipad tmply + // [self.view ] + for(UIView* view in self.view.subviews){ + [view removeFromSuperview]; + } + [self initParentStack]; + [self layoutSections]; + } + + + // [self swi]; + + self->slideToCloseSettingsViewRecognizer = [[CustomEdgeSlideGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)]; + slideToCloseSettingsViewRecognizer.edges = UIRectEdgeLeft; + slideToCloseSettingsViewRecognizer.normalizedThresholdDistance = 0.0; + slideToCloseSettingsViewRecognizer.EDGE_TOLERANCE = 10; + slideToCloseSettingsViewRecognizer.immediateTriggering = true; + slideToCloseSettingsViewRecognizer.delaysTouchesBegan = NO; + slideToCloseSettingsViewRecognizer.delaysTouchesEnded = NO; + [self.view addGestureRecognizer:slideToCloseSettingsViewRecognizer]; + + justEnteredSettingsViewDoNotOpenOscLayoutTool = true; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange) // handle orientation change since i made portrait mode available + name:UIDeviceOrientationDidChangeNotification + object:nil]; + + // Always run settings in dark mode because we want the light fonts + if (@available(iOS 13.0, tvOS 13.0, *)) { + self.overrideUserInterfaceStyle = UIUserInterfaceStyleDark; + } + + DataManager* dataMan = [[DataManager alloc] init]; + TemporarySettings* currentSettings = [dataMan getSettings]; + + currentSettingsMenuMode = currentSettings.settingsMenuMode.intValue; + [self loadFavoriteSettingStackIdentifiers]; + if(currentSettings.settingsMenuMode.intValue == FavoriteSettings) [self switchToFavoriteSettings]; + /* + switch (currentSettingsMenuMode) { + case FavoriteSettings: + [self switchToFavoriteSettings]; + break; + case AllSettings: + //[self switchToAllSettings]; + break; + default: + break; + } + */ + + + // Ensure we pick a bitrate that falls exactly onto a slider notch + _bitrate = bitrateTable[[self getSliderValueForBitrate:[currentSettings.bitrate intValue]]]; + + // Get the size of the screen with and without safe area insets + 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; + + [self.resolutionSelector removeSegmentAtIndex:0 animated:NO]; // remove 360p + [self.resolutionSelector removeSegmentAtIndex:5 animated:NO]; // remove custom segment + + resolutionTable[0] = CGSizeMake(1280, 720); + resolutionTable[1] = CGSizeMake(1920, 1080); + resolutionTable[2] = CGSizeMake(3840, 2160); + resolutionTable[3] = CGSizeMake(safeAreaWidth, fullScreenHeight); + resolutionTable[4] = CGSizeMake(fullScreenWidth, fullScreenHeight); + resolutionTable[5] = CGSizeMake([currentSettings.width integerValue], [currentSettings.height integerValue]); // custom initial value + [self updateResolutionTable]; + + // Don't populate the custom entry unless we have a custom resolution + //self.customResolutionSwitch + if (!isCustomResolution(resolutionTable[5])) { + resolutionTable[5] = CGSizeMake(0, 0); + } + + NSInteger framerate; + switch ([currentSettings.framerate integerValue]) { + case 30: + framerate = 0; + break; + default: + case 60: + framerate = 1; + break; + case 120: + framerate = 2; + break; + } + + NSInteger resolution = currentSettings.resolutionSelected.integerValue; + if(resolution >= RESOLUTION_TABLE_SIZE){ + resolution = 0; + } + + // Only show the 120 FPS option if we have a > 60-ish Hz display + bool enable120Fps = false; + if (@available(iOS 10.3, tvOS 10.3, *)) { + if ([UIScreen mainScreen].maximumFramesPerSecond > 62) { + enable120Fps = true; + } + } + if (!enable120Fps) { + [self.framerateSelector removeSegmentAtIndex:2 animated:NO]; + } + + // Disable codec selector segments for unsupported codecs + #if defined(__IPHONE_16_0) || defined(__TVOS_16_0) + if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_AV1)) + #endif + { + [self.codecSelector removeSegmentAtIndex:2 animated:NO]; + } + if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { + [self.codecSelector removeSegmentAtIndex:1 animated:NO]; - // Don't populate the custom entry unless we have a custom resolution - //self.customResolutionSwitch - if (!isCustomResolution(resolutionTable[5])) { - resolutionTable[5] = CGSizeMake(0, 0); - } - - NSInteger framerate; - switch ([currentSettings.framerate integerValue]) { - case 30: - framerate = 0; - break; - default: - case 60: - framerate = 1; - break; - case 120: - framerate = 2; - break; - } - - NSInteger resolution = currentSettings.resolutionSelected.integerValue; - if(resolution >= RESOLUTION_TABLE_SIZE){ - resolution = 0; - } - - // Only show the 120 FPS option if we have a > 60-ish Hz display - bool enable120Fps = false; - if (@available(iOS 10.3, tvOS 10.3, *)) { - if ([UIScreen mainScreen].maximumFramesPerSecond > 62) { - enable120Fps = true; - } - } - if (!enable120Fps) { - [self.framerateSelector removeSegmentAtIndex:2 animated:NO]; - } - - // Disable codec selector segments for unsupported codecs -#if defined(__IPHONE_16_0) || defined(__TVOS_16_0) - if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_AV1)) -#endif - { - [self.codecSelector removeSegmentAtIndex:2 animated:NO]; - } - if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC)) { - [self.codecSelector removeSegmentAtIndex:1 animated:NO]; + // Only enable the 4K option for "recent" devices. We'll judge that by whether + // they support HEVC decoding (A9 or later). + [self.resolutionSelector setEnabled:NO forSegmentAtIndex:3]; + } + switch (currentSettings.preferredCodec) { + case CODEC_PREF_AUTO: + [self.codecSelector setSelectedSegmentIndex:self.codecSelector.numberOfSegments - 1]; + break; - // Only enable the 4K option for "recent" devices. We'll judge that by whether - // they support HEVC decoding (A9 or later). - [self.resolutionSelector setEnabled:NO forSegmentAtIndex:3]; - } - switch (currentSettings.preferredCodec) { - case CODEC_PREF_AUTO: - [self.codecSelector setSelectedSegmentIndex:self.codecSelector.numberOfSegments - 1]; - break; - - case CODEC_PREF_AV1: - [self.codecSelector setSelectedSegmentIndex:2]; - break; - - case CODEC_PREF_HEVC: - [self.codecSelector setSelectedSegmentIndex:1]; - break; - - case CODEC_PREF_H264: - [self.codecSelector setSelectedSegmentIndex:0]; - break; - } - - if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC) || !(AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10)) { - [self.hdrSwitch setOn:NO]; - [self.hdrSwitch setEnabled:NO]; - } - else { - [self.hdrSwitch setOn:currentSettings.enableHdr]; - } - - [self.yuv444Switch setOn:currentSettings.enableYUV444]; - [self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue]; - [self.citrixX1MouseSwitch setOn:currentSettings.btMouseSupport]; - [self.optimizeGamesSwitch setOn: currentSettings.optimizeGames]; - [self.framePacingSelector setSelectedSegmentIndex:currentSettings.useFramePacing ? 1 : 0]; - [self.multiControllerSwitch setOn:currentSettings.multiController]; - [self.swapABXYButtonsSelector setSelectedSegmentIndex:currentSettings.swapABXYButtons ? 1 : 0]; - [self.audioOnPcSwitch setOn:currentSettings.playAudioOnPC]; - _lastSelectedResolutionIndex = resolution; - [self.resolutionSelector setSelectedSegmentIndex:resolution]; - [self.resolutionSelector addTarget:self action:@selector(newResolutionChosen) forControlEvents:UIControlEventValueChanged]; - [self.customResolutionSwitch addTarget:self action:@selector(customResolutionSwitched:) forControlEvents:UIControlEventValueChanged]; - CGSize currentResolution = CGSizeMake(currentSettings.width.intValue, currentSettings.height.intValue); - [self.customResolutionSwitch setOn: isCustomResolution(currentResolution)]; - - [self.framerateSelector setSelectedSegmentIndex:framerate]; - [self.framerateSelector addTarget:self action:@selector(updateBitrate) forControlEvents:UIControlEventValueChanged]; - [self.bitrateSlider setMinimumValue:0]; - [self.bitrateSlider setMaximumValue:(sizeof(bitrateTable) / sizeof(*bitrateTable)) - 1]; - [self.bitrateSlider setValue:[self getSliderValueForBitrate:_bitrate] animated:YES]; - [self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged]; - [self updateBitrateText]; - [self updateResolutionDisplayLabel]; - - // Unlock Display Orientation setting - bool unlockDisplayOrientationSelectorEnabled = [self isFullScreenRequired];//need "requires fullscreen" enabled in the app bunddle to make runtime orientation limitation woring - if(unlockDisplayOrientationSelectorEnabled) [self.unlockDisplayOrientationSelector setSelectedSegmentIndex:currentSettings.unlockDisplayOrientation ? 1 : 0]; - else [self.unlockDisplayOrientationSelector setSelectedSegmentIndex:1]; // can't lock screen orientation in this mode = Display Orientation always unlocked - [self.unlockDisplayOrientationSelector setEnabled:unlockDisplayOrientationSelectorEnabled]; - - - // lift streamview setting - [self.liftStreamViewForKeyboardSelector setSelectedSegmentIndex:currentSettings.liftStreamViewForKeyboard ? 1 : 0];// Load old setting - - // showkeyboard toolbar setting - [self.softKeyboardToolbarSwitch setOn:currentSettings.showKeyboardToolbar];// Load old setting - - // reverse mouse wheel direction setting - [self.reverseMouseWheelDirectionSelector setSelectedSegmentIndex:currentSettings.reverseMouseWheelDirection ? 1 : 0];// Load old setting - - // slide to menu settings - [self.slideToSettingsScreenEdgeSelector setSelectedSegmentIndex:[self getSelectorIndexFromScreenEdge:(uint32_t)currentSettings.slideToSettingsScreenEdge.integerValue]]; - // Load old setting - [self.slideToToolboxScreenEdgeSelector setEnabled:false]; - [self.slideToSettingsScreenEdgeSelector addTarget:self action:@selector(slideToSettingsScreenEdgeChanged) forControlEvents:UIControlEventValueChanged]; - [self slideToSettingsScreenEdgeChanged]; - - [self.slideToMenuDistanceSlider setValue:currentSettings.slideToSettingsDistance.floatValue]; + case CODEC_PREF_AV1: + [self.codecSelector setSelectedSegmentIndex:2]; + break; + + case CODEC_PREF_HEVC: + [self.codecSelector setSelectedSegmentIndex:1]; + break; + + case CODEC_PREF_H264: + [self.codecSelector setSelectedSegmentIndex:0]; + break; + } + + if (!VTIsHardwareDecodeSupported(kCMVideoCodecType_HEVC) || !(AVPlayer.availableHDRModes & AVPlayerHDRModeHDR10)) { + [self.hdrSwitch setOn:NO]; + [self.hdrSwitch setEnabled:NO]; + } + else { + [self.hdrSwitch setOn:currentSettings.enableHdr]; + } + + [self.yuv444Switch setOn:currentSettings.enableYUV444]; + [self.statsOverlaySelector setSelectedSegmentIndex:currentSettings.statsOverlayLevel.intValue]; + [self.citrixX1MouseSwitch setOn:currentSettings.btMouseSupport]; + [self.optimizeGamesSwitch setOn: currentSettings.optimizeGames]; + [self.framePacingSelector setSelectedSegmentIndex:currentSettings.useFramePacing ? 1 : 0]; + [self.multiControllerSwitch setOn:currentSettings.multiController]; + [self.swapABXYButtonsSelector setSelectedSegmentIndex:currentSettings.swapABXYButtons ? 1 : 0]; + [self.audioOnPcSwitch setOn:currentSettings.playAudioOnPC]; + _lastSelectedResolutionIndex = resolution; + [self.resolutionSelector setSelectedSegmentIndex:resolution]; + [self.resolutionSelector addTarget:self action:@selector(newResolutionChosen) forControlEvents:UIControlEventValueChanged]; + [self.customResolutionSwitch addTarget:self action:@selector(customResolutionSwitched:) forControlEvents:UIControlEventValueChanged]; + CGSize currentResolution = CGSizeMake(currentSettings.width.intValue, currentSettings.height.intValue); + [self.customResolutionSwitch setOn: isCustomResolution(currentResolution)]; + + [self.framerateSelector setSelectedSegmentIndex:framerate]; + [self.framerateSelector addTarget:self action:@selector(updateBitrate) forControlEvents:UIControlEventValueChanged]; + [self.bitrateSlider setMinimumValue:0]; + [self.bitrateSlider setMaximumValue:(sizeof(bitrateTable) / sizeof(*bitrateTable)) - 1]; + [self.bitrateSlider setValue:[self getSliderValueForBitrate:_bitrate] animated:YES]; + [self.bitrateSlider addTarget:self action:@selector(bitrateSliderMoved) forControlEvents:UIControlEventValueChanged]; + [self updateBitrateText]; + [self updateResolutionDisplayLabel]; + + // Unlock Display Orientation setting + bool unlockDisplayOrientationSelectorEnabled = [self isFullScreenRequired];//need "requires fullscreen" enabled in the app bunddle to make runtime orientation limitation woring + if(unlockDisplayOrientationSelectorEnabled) [self.unlockDisplayOrientationSelector setSelectedSegmentIndex:currentSettings.unlockDisplayOrientation ? 1 : 0]; + else [self.unlockDisplayOrientationSelector setSelectedSegmentIndex:1]; // can't lock screen orientation in this mode = Display Orientation always unlocked + [self.unlockDisplayOrientationSelector setEnabled:unlockDisplayOrientationSelectorEnabled]; + + + // lift streamview setting + [self.liftStreamViewForKeyboardSelector setSelectedSegmentIndex:currentSettings.liftStreamViewForKeyboard ? 1 : 0];// Load old setting + + // showkeyboard toolbar setting + [self.softKeyboardToolbarSwitch setOn:currentSettings.showKeyboardToolbar];// Load old setting + + // reverse mouse wheel direction setting + [self.reverseMouseWheelDirectionSelector setSelectedSegmentIndex:currentSettings.reverseMouseWheelDirection ? 1 : 0];// Load old setting + + // slide to menu settings + [self.slideToSettingsScreenEdgeSelector setSelectedSegmentIndex:[self getSelectorIndexFromScreenEdge:(uint32_t)currentSettings.slideToSettingsScreenEdge.integerValue]]; + // Load old setting + [self.slideToToolboxScreenEdgeSelector setEnabled:false]; + [self.slideToSettingsScreenEdgeSelector addTarget:self action:@selector(slideToSettingsScreenEdgeChanged) forControlEvents:UIControlEventValueChanged]; + [self slideToSettingsScreenEdgeChanged]; + + [self.slideToMenuDistanceSlider setValue:currentSettings.slideToSettingsDistance.floatValue]; [self.slideToMenuDistanceSlider addTarget:self action:@selector(slideToMenuDistanceSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self slideToMenuDistanceSliderMoved:self.slideToMenuDistanceSlider]; - - - - //TouchMode & OSC Related Settings: - - // pointer veloc setting, will be enable/disabled by touchMode - [self.pointerVelocityModeDividerSlider setValue: (uint8_t)(currentSettings.pointerVelocityModeDivider.floatValue * 100) animated:YES]; // Load old setting. - [self.pointerVelocityModeDividerSlider addTarget:self action:@selector(pointerVelocityModeDividerSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. - [self pointerVelocityModeDividerSliderMoved:self.pointerVelocityModeDividerSlider]; - - // init pointer veloc setting, will be enable/disabled by touchMode - [self.touchPointerVelocityFactorSlider setValue: [self map_SliderValue_fromVelocFactor: currentSettings.touchPointerVelocityFactor.floatValue] animated:YES]; // Load old setting. - [self.touchPointerVelocityFactorSlider addTarget:self action:@selector(touchPointerVelocityFactorSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. - [self touchPointerVelocityFactorSliderMoved:self.touchPointerVelocityFactorSlider]; - - // async native touch event - // [self.asyncNativeTouchPrioritySelector setSelectedSegmentIndex:currentSettings.asyncNativeTouchPriority.intValue]; // load old setting of asyncNativeTouchPriority - // [self.asyncNativeTouchPrioritySelector addTarget:self action:@selector(asyncNativeTouchPriorityChanged) forControlEvents:UIControlEventValueChanged]; - - // init relative touch mouse pointer veloc setting, will be enable/disabled by touchMode - [self.mousePointerVelocityFactorSlider setValue:[self map_SliderValue_fromVelocFactor: currentSettings.mousePointerVelocityFactor.floatValue] animated:YES]; // Load old setting. - [self.mousePointerVelocityFactorSlider addTarget:self action:@selector(mousePointerVelocityFactorSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. - [self mousePointerVelocityFactorSliderMoved:self.mousePointerVelocityFactorSlider]; - - - // these settings will be affected by onscreenControl & touchMode, must be loaded before them. - // NSLog(@"osc tool fingers setting test: %d", currentSettings.oscLayoutToolFingers.intValue); - self->oswLayoutFingers = (uint16_t)currentSettings.oscLayoutToolFingers.intValue; // load old setting of oscLayoutFingers + + + + //TouchMode & OSC Related Settings: + + // pointer veloc setting, will be enable/disabled by touchMode + [self.pointerVelocityModeDividerSlider setValue: (uint8_t)(currentSettings.pointerVelocityModeDivider.floatValue * 100) animated:YES]; // Load old setting. + [self.pointerVelocityModeDividerSlider addTarget:self action:@selector(pointerVelocityModeDividerSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. + [self pointerVelocityModeDividerSliderMoved:self.pointerVelocityModeDividerSlider]; + + // init pointer veloc setting, will be enable/disabled by touchMode + [self.touchPointerVelocityFactorSlider setValue: [self map_SliderValue_fromVelocFactor: currentSettings.touchPointerVelocityFactor.floatValue] animated:YES]; // Load old setting. + [self.touchPointerVelocityFactorSlider addTarget:self action:@selector(touchPointerVelocityFactorSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. + [self touchPointerVelocityFactorSliderMoved:self.touchPointerVelocityFactorSlider]; + + // async native touch event + // [self.asyncNativeTouchPrioritySelector setSelectedSegmentIndex:currentSettings.asyncNativeTouchPriority.intValue]; // load old setting of asyncNativeTouchPriority + // [self.asyncNativeTouchPrioritySelector addTarget:self action:@selector(asyncNativeTouchPriorityChanged) forControlEvents:UIControlEventValueChanged]; + + // init relative touch mouse pointer veloc setting, will be enable/disabled by touchMode + [self.mousePointerVelocityFactorSlider setValue:[self map_SliderValue_fromVelocFactor: currentSettings.mousePointerVelocityFactor.floatValue] animated:YES]; // Load old setting. + [self.mousePointerVelocityFactorSlider addTarget:self action:@selector(mousePointerVelocityFactorSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. + [self mousePointerVelocityFactorSliderMoved:self.mousePointerVelocityFactorSlider]; + + + // these settings will be affected by onscreenControl & touchMode, must be loaded before them. + // NSLog(@"osc tool fingers setting test: %d", currentSettings.oscLayoutToolFingers.intValue); + self->oswLayoutFingers = (uint16_t)currentSettings.oscLayoutToolFingers.intValue; // load old setting of oscLayoutFingers uint8_t keyboardToggleFingers = currentSettings.keyboardToggleFingers.intValue; - + [self.softKeyboardGestureSelector setSelectedSegmentIndex:keyboardToggleFingers>=5 ? 3 : keyboardToggleFingers-3]; - - - - // this setting will be affected by touchMode, must be loaded before them. - NSInteger onscreenControlsLevel = [currentSettings.onscreenControls integerValue]; - [self.onScreenWidgetSelector setSelectedSegmentIndex:onscreenControlsLevel]; - [self.onScreenWidgetSelector addTarget:self action:@selector(onScreenWidgetChanged) forControlEvents:UIControlEventValueChanged]; - [self onScreenWidgetChanged]; - - // touch move event interval for native-touch. - [self.touchMoveEventIntervalSlider setValue:currentSettings.touchMoveEventInterval.intValue animated:YES]; // Load old setting. + + + + // this setting will be affected by touchMode, must be loaded before them. + NSInteger onscreenControlsLevel = [currentSettings.onscreenControls integerValue]; + [self.onScreenWidgetSelector setSelectedSegmentIndex:onscreenControlsLevel]; + [self.onScreenWidgetSelector addTarget:self action:@selector(onScreenWidgetChanged) forControlEvents:UIControlEventValueChanged]; + [self onScreenWidgetChanged]; + + // touch move event interval for native-touch. + [self.touchMoveEventIntervalSlider setValue:currentSettings.touchMoveEventInterval.intValue animated:YES]; // Load old setting. [self.touchMoveEventIntervalSlider addTarget:self action:@selector(touchMoveEventIntervalSliderMoved:) forControlEvents:(UIControlEventValueChanged)]; // Update label display when slider is being moved. [self touchMoveEventIntervalSliderMoved:self.touchMoveEventIntervalSlider]; - - - // this part will enable/disable oscSelector & the asyncNativeTouchPriority selector - uint8_t touchModeSelectorIndex = currentSettings.touchMode.intValue == NativeTouchOnly ? NativeTouch : currentSettings.touchMode.intValue; - [self.touchModeSelector setSelectedSegmentIndex:touchModeSelectorIndex]; //Load old touchMode setting - [self.touchModeSelector addTarget:self action:@selector(touchModeChanged:) forControlEvents:UIControlEventValueChanged]; - [self touchModeChanged:self.touchModeSelector]; - self.enableOswSwitchStack.hidden = !(currentSettings.touchMode.intValue == NativeTouch || currentSettings.touchMode.intValue == NativeTouchOnly); - [self.enableOswForNativeTouchSwitch setOn:currentSettings.touchMode.intValue != NativeTouchOnly]; - [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]; + + // this part will enable/disable oscSelector & the asyncNativeTouchPriority selector + uint8_t touchModeSelectorIndex = currentSettings.touchMode.intValue == NativeTouchOnly ? NativeTouch : currentSettings.touchMode.intValue; + [self.touchModeSelector setSelectedSegmentIndex:touchModeSelectorIndex]; //Load old touchMode setting + [self.touchModeSelector addTarget:self action:@selector(touchModeChanged:) forControlEvents:UIControlEventValueChanged]; + [self touchModeChanged:self.touchModeSelector]; + + self.enableOswSwitchStack.hidden = !(currentSettings.touchMode.intValue == NativeTouch || currentSettings.touchMode.intValue == NativeTouchOnly); + [self.enableOswForNativeTouchSwitch setOn:currentSettings.touchMode.intValue != NativeTouchOnly]; + [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]; } - (void)slideToSettingsScreenEdgeChanged{ @@ -1603,22 +1627,38 @@ BOOL isCustomResolution(CGSize res) { bool isNativeTouch = sender.selectedSegmentIndex == NativeTouch; //bool asyncNativeTouchEnabled = [self.asyncNativeTouchPrioritySelector selectedSegmentIndex] != AsyncNativeTouchOff; self.enableOswSwitchStack.hidden = !isNativeTouch; + [self setHidden:!isNativeTouch forStack:self.pointerVelocityDividerStack]; + // [self.asyncNativeTouchPrioritySelector setEnabled:![self showOswSelector]]; // this selector stay aligned with oscSelector - [self.touchMoveEventIntervalSlider setEnabled: isNativeTouch]; [self touchMoveEventIntervalSliderMoved:self.touchMoveEventIntervalSlider]; - self.pointerVelocityDividerStack.hidden = !isNativeTouch; - self.pointerVelocityFactorStack.hidden = !isNativeTouch; - self.mousePointerVelocityStack.hidden = !(sender.selectedSegmentIndex == RelativeTouch); - - self.onScreenWidgetStack.hidden = ![self isNotNativeTouchOnly]; - self.swapAbaxyStack.hidden = ![self isNotNativeTouchOnly]; + [self setHidden:!isNativeTouch forStack:self.pointerVelocityDividerStack]; + [self setHidden:!isNativeTouch forStack:self.pointerVelocityFactorStack]; + + [self setHidden:!(sender.selectedSegmentIndex == RelativeTouch) forStack:self.mousePointerVelocityStack]; + [self setHidden:![self isNotNativeTouchOnly] forStack:self.onScreenWidgetStack]; + [self setHidden:![self isNotNativeTouchOnly] forStack:self.swapAbaxyStack]; + [touchControlSection updateViewForFoldState]; } +- (void)setHidden:(BOOL)hidden forStack:(UIStackView* )stack{ + // CGFloat previousSpacing = stack.spacing; + if(hidden){ + stack.hidden = YES; + [hiddenStacks addObject:stack]; + } + else{ + stack.hidden = NO; + [hiddenStacks removeObject:stack]; + } +} + - (void)enableOswForNativeTouchSwitchFlipped:(UISwitch *)sender{ - self.onScreenWidgetStack.hidden = !sender.isOn; - self.swapAbaxyStack.hidden = !sender.isOn; + //self.onScreenWidgetStack.hidden = !sender.isOn; + [self setHidden:!sender.isOn forStack:_onScreenWidgetStack]; + [self setHidden:!sender.isOn forStack:_swapAbaxyStack]; + //self.swapAbaxyStack.hidden = !sender.isOn; [touchControlSection updateViewForFoldState]; } diff --git a/Limelight/ViewControllers/ToolBoxViewController.swift b/Limelight/ViewControllers/ToolBoxViewController.swift index e452df67..a09bbe80 100644 --- a/Limelight/ViewControllers/ToolBoxViewController.swift +++ b/Limelight/ViewControllers/ToolBoxViewController.swift @@ -8,12 +8,14 @@ import UIKit +@objc protocol ToolBoxSpecialEntryDelegate: NSObjectProtocol { + @objc optional func openWidgetLayoutTool() + @objc optional func switchWidgetProfile() +} + + @objc public class ToolBoxViewController: UIViewController, UITableViewDataSource, UITableViewDelegate { - @objc protocol ToolBoxSpecialEntryDelegate: NSObjectProtocol { - @objc optional func openWidgetLayoutTool() - @objc optional func switchWidgetProfile() - } @objc weak var specialEntryDelegate: ToolBoxSpecialEntryDelegate? public let tableView = UITableView() private let addButton = UIButton(type: .system)