old iOS compatibility fixes:

- strong settingButton reference
- hidden stackView heightContraint
- navBarAppearance
This commit is contained in:
TrueZhuangjia
2025-06-15 23:01:22 +08:00
committed by TrueZhuanjia
parent fb32ef3629
commit 1737eae39b
9 changed files with 454 additions and 383 deletions
+12 -11
View File
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="23727" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="EVd-wq-ego">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="EVd-wq-ego">
<device id="ipad11_0rounded" orientation="portrait" layout="fullscreen" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="23721"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -12,7 +12,7 @@
<objects>
<viewController id="wb7-af-jn8" customClass="MainFrameViewController" sceneMemberID="viewController">
<collectionView key="view" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" indicatorStyle="black" dataMode="prototypes" id="TZj-Lc-M9d" customClass="AppCollectionView">
<rect key="frame" x="0.0" y="0.0" width="834" height="1136"/>
<rect key="frame" x="0.0" y="0.0" width="834" height="1120"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<collectionViewFlowLayout key="collectionViewLayout" minimumLineSpacing="20" minimumInteritemSpacing="20" id="f7l-kG-hJc">
@@ -63,8 +63,8 @@
<rect key="frame" x="0.0" y="0.0" width="682" height="2500"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="7" translatesAutoresizingMaskIntoConstraints="NO" id="zpX-lo-MLA" userLabel="Resolutionstak">
<rect key="frame" x="16" y="57" width="380" height="96.5"/>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="zpX-lo-MLA" userLabel="Resolutionstak">
<rect key="frame" x="16" y="57" width="380" height="92.5"/>
<subviews>
<label opaque="NO" clearsContextBeforeDrawing="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Resolution " lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="pYZ-GR-EwO">
<rect key="frame" x="0.0" y="0.0" width="380" height="20.5"/>
@@ -74,7 +74,7 @@
<size key="shadowOffset" width="0.0" height="0.0"/>
</label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" apportionsSegmentWidthsByContent="YES" segmentControlStyle="plain" selectedSegmentIndex="5" translatesAutoresizingMaskIntoConstraints="NO" id="ckc-Dm-8ex">
<rect key="frame" x="0.0" y="27.5" width="380" height="32"/>
<rect key="frame" x="0.0" y="25.5" width="380" height="32"/>
<segments>
<segment title="360p" enabled="NO"/>
<segment title="720p"/>
@@ -88,7 +88,7 @@
<color key="selectedSegmentTintColor" systemColor="linkColor"/>
</segmentedControl>
<stackView opaque="NO" contentMode="scaleToFill" spacing="20" translatesAutoresizingMaskIntoConstraints="NO" id="djj-8b-2pB" userLabel="ResolutionInnerStack2">
<rect key="frame" x="0.0" y="65.5" width="380" height="31"/>
<rect key="frame" x="0.0" y="61.5" width="380" height="31"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Custom Resolution" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hq8-dy-8BF">
<rect key="frame" x="0.0" y="0.0" width="130" height="31"/>
@@ -396,6 +396,7 @@
</subviews>
<constraints>
<constraint firstAttribute="width" constant="380" id="RoD-rl-0Us"/>
<constraint firstAttribute="height" priority="999" constant="56.5" id="t3w-8N-xWr"/>
</constraints>
</stackView>
<stackView opaque="NO" contentMode="scaleToFill" ambiguous="YES" axis="vertical" spacing="5" translatesAutoresizingMaskIntoConstraints="NO" id="2GS-cX-u4i" userLabel="swapABXYButtons Stack">
@@ -876,7 +877,7 @@
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="01j-TU-OoL" userLabel="First Responder" sceneMemberID="firstResponder"/>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="video.and.waveform" catalog="system" id="20f-ao-iK1">
<rect key="frame" x="0.0" y="0.0" width="240" height="128"/>
<rect key="frame" x="0.0" y="-4" width="240" height="128"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
</imageView>
<navigationBar contentMode="scaleToFill" id="3qa-QW-sSl">
@@ -898,7 +899,7 @@
<viewControllerLayoutGuide type="bottom" id="YRO-Lg-RCg"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="hGs-BR-t4b">
<rect key="frame" x="0.0" y="0.0" width="834" height="1210"/>
<rect key="frame" x="0.0" y="0.0" width="834" height="1194"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
@@ -937,7 +938,7 @@
<viewControllerLayoutGuide type="bottom" id="vu8-3s-HlY"/>
</layoutGuides>
<view key="view" multipleTouchEnabled="YES" contentMode="scaleToFill" id="SMn-1j-R3I">
<rect key="frame" x="0.0" y="0.0" width="834" height="1210"/>
<rect key="frame" x="0.0" y="0.0" width="834" height="1194"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" red="0.3333357871" green="0.33332890269999998" blue="0.33333355190000002" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</view>
@@ -959,7 +960,7 @@
<viewControllerLayoutGuide type="bottom" id="YZj-An-sqS"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="le1-tU-NEp">
<rect key="frame" x="0.0" y="0.0" width="834" height="1210"/>
<rect key="frame" x="0.0" y="0.0" width="834" height="1194"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<activityIndicatorView opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" animating="YES" style="whiteLarge" translatesAutoresizingMaskIntoConstraints="NO" id="N0D-dj-EuF">
+4 -2
View File
@@ -9,9 +9,11 @@
// MenuSectionView.h
#import <UIKit/UIKit.h>
#import "DataManager.h"
@protocol HideOverlappedDynamicLabelDelegate <NSObject>
@protocol MenuSectionDelegate <NSObject>
- (void)hideOverlappedDynamicLabels;
- (SettingsMenuMode)getSettingsMenuMode;
@end
@@ -27,7 +29,7 @@
@property (nonatomic, assign) CGFloat headerViewHeight;
@property (nonatomic, assign) CGFloat headerViewVerticalSpacing;
@property (nonatomic, strong) NSMutableArray<UIStackView *> *subStackViews;
@property (nonatomic, weak) id<HideOverlappedDynamicLabelDelegate> delegate; // Delegate property
@property (nonatomic, weak) id<MenuSectionDelegate> delegate; // Delegate property
// 方法
- (void)setSectionWithIcon:(UIImage *)icon andSize:(CGFloat)size;
+11
View File
@@ -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;
@@ -23,7 +23,7 @@
@interface MainFrameViewController : UICollectionViewController <DiscoveryCallback, PairCallback, HostCallback, AppCallback, AppAssetCallback, NSURLConnectionDelegate, SWRevealViewControllerDelegate, HostCardActionDelegate>
@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;
@@ -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 {
@@ -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{
@@ -16,42 +16,42 @@
#import "CustomEdgeSlideGestureRecognizer.h"
#import "MenuSectionView.h"
@interface SettingsViewController : UIViewController <RearNavigationBarMenuDelegate, HideOverlappedDynamicLabelDelegate>
@interface SettingsViewController : UIViewController <RearNavigationBarMenuDelegate, MenuSectionDelegate>
@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
+332 -292
View File
@@ -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];
}
@@ -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)