From 2775ca09c7de5a11d7d2e050981cc43b6b4ac272 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Tue, 3 Jun 2025 20:58:04 +0800 Subject: [PATCH] - settings menu nav more bar button and separatorLine - settings menu hit test --- Limelight/Base.lproj/iPad.storyboard | 277 +++++++++-------- Limelight/Base.lproj/iPhone.storyboard | 15 +- Limelight/HostCardView.m | 2 - .../disconnect.imageset/Contents.json | 21 ++ .../disconnect.imageset/disconnect.svg | 7 + Limelight/MenuSectionView.m | 17 +- Limelight/ThemeManager.m | 7 +- Limelight/UIAppView.m | 1 - .../HostCollectionViewController.m | 18 +- .../ViewControllers/MainFrameViewController.h | 1 - .../ViewControllers/MainFrameViewController.m | 166 +++++++---- .../ViewControllers/SWRevealViewController.h | 7 +- .../ViewControllers/SWRevealViewController.m | 281 +++++++++++++++--- .../ViewControllers/SettingsViewController.h | 8 +- .../ViewControllers/SettingsViewController.m | 161 +++++++++- .../StreamFrameViewController.m | 2 - 16 files changed, 722 insertions(+), 269 deletions(-) create mode 100644 Limelight/Images.xcassets/disconnect.imageset/Contents.json create mode 100644 Limelight/Images.xcassets/disconnect.imageset/disconnect.svg diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard index 42081400..c9240cef 100644 --- a/Limelight/Base.lproj/iPad.storyboard +++ b/Limelight/Base.lproj/iPad.storyboard @@ -64,17 +64,17 @@ - + - - - + - + - + @@ -119,39 +116,39 @@ - + - + - + - + - + - + @@ -163,21 +160,21 @@ - + - + - + @@ -187,14 +184,14 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -297,14 +294,14 @@ - + - + - + - + - + - + @@ -346,21 +343,21 @@ ICAgICAgICAgICAgICA - + - + - + @@ -370,21 +367,21 @@ ICAgICAgICAgICAgICA - + - + - + @@ -394,21 +391,21 @@ ICAgICAgICAgICAgICA - + - + - + @@ -419,41 +416,41 @@ ICAgICAgICAgICAgICA - + - + - - + - + - + @@ -463,20 +460,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -486,20 +483,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -509,20 +506,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -532,20 +529,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -557,20 +554,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -580,20 +577,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -603,20 +600,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -626,20 +623,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -649,20 +646,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -672,20 +669,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -696,20 +693,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -719,20 +716,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -742,20 +739,20 @@ ICAgICAgICAgICAgICA - + - + - + @@ -766,11 +763,11 @@ ICAgICAgICAgICAgICA - + - + @@ -858,7 +855,7 @@ ICAgICAgICAgICAgICA - + @@ -889,8 +886,7 @@ ICAgICAgICAgICAgICA - - + @@ -898,7 +894,7 @@ ICAgICAgICAgICAgICA - + @@ -1271,16 +1267,13 @@ ICAgICAgICAgICAgICA - + - - - - + diff --git a/Limelight/Base.lproj/iPhone.storyboard b/Limelight/Base.lproj/iPhone.storyboard index 90c47271..660ba759 100644 --- a/Limelight/Base.lproj/iPhone.storyboard +++ b/Limelight/Base.lproj/iPhone.storyboard @@ -1,9 +1,9 @@ - + - + @@ -13,7 +13,7 @@ - + @@ -43,7 +43,8 @@ - + + @@ -648,7 +649,7 @@ ICAgICAgICAgICAgIA - + @@ -955,12 +956,12 @@ ICAgICAgICAgICAgIA - + - + diff --git a/Limelight/HostCardView.m b/Limelight/HostCardView.m index 6a31fe28..21c1039b 100644 --- a/Limelight/HostCardView.m +++ b/Limelight/HostCardView.m @@ -61,7 +61,6 @@ static const float REFRESH_CYCLE = 2.0f; defaultGreen = [UIColor colorWithRed:52.0/255.0 green:199.0/255.0 blue:89.0/255.0 alpha:1.0]; // self.userIterfaceStyle = UIUserInterfaceStyleLight if (@available(iOS 13.0, *)) { - NSLog(@"ttesttttt"); UIContextMenuInteraction* longPressInteraction = [[UIContextMenuInteraction alloc] initWithDelegate:self]; [self addInteraction:longPressInteraction]; self.userInteractionEnabled = YES; @@ -154,7 +153,6 @@ static const float REFRESH_CYCLE = 2.0f; - (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location API_AVAILABLE(ios(13.0)){ - NSLog(@"long tap test"); longPressFired = true; if ([self.delegate respondsToSelector:@selector(hostCardLongPressed:view:)]) { [self.delegate hostCardLongPressed:_host view:self]; diff --git a/Limelight/Images.xcassets/disconnect.imageset/Contents.json b/Limelight/Images.xcassets/disconnect.imageset/Contents.json new file mode 100644 index 00000000..9f10bd77 --- /dev/null +++ b/Limelight/Images.xcassets/disconnect.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "disconnect.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Limelight/Images.xcassets/disconnect.imageset/disconnect.svg b/Limelight/Images.xcassets/disconnect.imageset/disconnect.svg new file mode 100644 index 00000000..75d1b5f3 --- /dev/null +++ b/Limelight/Images.xcassets/disconnect.imageset/disconnect.svg @@ -0,0 +1,7 @@ + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon + + \ No newline at end of file diff --git a/Limelight/MenuSectionView.m b/Limelight/MenuSectionView.m index 6df6311e..3b12b415 100644 --- a/Limelight/MenuSectionView.m +++ b/Limelight/MenuSectionView.m @@ -8,6 +8,7 @@ // MenuSectionView.m #import "MenuSectionView.h" +#import "ThemeManager.h" @interface MenuSectionView () @@ -67,13 +68,14 @@ _iconImageView = [[UIImageView alloc] init]; _iconImageView.contentMode = UIViewContentModeScaleAspectFit; _iconImageView.translatesAutoresizingMaskIntoConstraints = NO; - _iconImageView.tintColor = [UIColor whiteColor]; + _iconImageView.tintColor = [ThemeManager textColor]; [_headerView addSubview:_iconImageView]; // 标题标签 _titleLabel = [[UILabel alloc] init]; _titleLabel.text = _sectionTitle; _titleLabel.font = [UIFont systemFontOfSize:27 weight:UIFontWeightMedium]; + _titleLabel.textColor = [ThemeManager textColor]; _titleLabel.textAlignment = NSTextAlignmentLeft; _titleLabel.translatesAutoresizingMaskIntoConstraints = NO; [_headerView addSubview:_titleLabel]; @@ -105,7 +107,7 @@ // 分隔线 _separatorLine = [[UIView alloc] init]; - _separatorLine.backgroundColor = [UIColor colorWithWhite:0.2 alpha:5.0]; + _separatorLine.backgroundColor = [ThemeManager separatorColor]; _separatorLine.translatesAutoresizingMaskIntoConstraints = NO; [self addSubview:_separatorLine]; @@ -187,7 +189,14 @@ #pragma mark - Public Methods - (void)setSectionIcon:(UIImage *)icon { - _iconImageView.image = icon; + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithWeight:UIImageSymbolWeightSemibold]; + _iconImageView.image = [icon imageWithConfiguration:config]; + + } else { + _iconImageView.image = icon; + } + _iconImageView.hidden = (icon == nil); [self updateLayout]; } @@ -287,7 +296,7 @@ [self setupConstraints]; if (_expanded) { _rootStackView.hidden = NO; - _separatorLine.hidden = NO; + _separatorLine.hidden = YES; CGSize fittingSize = [self.rootStackView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; CGFloat rootStackViewHeight = fittingSize.height; fittingSize = [self.headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; diff --git a/Limelight/ThemeManager.m b/Limelight/ThemeManager.m index 21cb4e6c..2e145f5b 100644 --- a/Limelight/ThemeManager.m +++ b/Limelight/ThemeManager.m @@ -47,6 +47,7 @@ static UIUserInterfaceStyle _userInterfaceStyle; case UIUserInterfaceStyleDark: default: return [UIColor colorWithRed:28.0/255.0 green:28.0/255.0 blue:30.0/255.0 alpha:1.0]; + //return [UIColor blackColor]; break; } } @@ -68,12 +69,10 @@ static UIUserInterfaceStyle _userInterfaceStyle; [ThemeManager getUIStyle]; switch (self.userInterfaceStyle) { case UIUserInterfaceStyleLight: - NSLog(@"themeLightSP"); return [UIColor colorWithWhite:0.1 alpha:0.28]; break; case UIUserInterfaceStyleDark: default: - NSLog(@"themeDarkSP"); return [UIColor colorWithWhite:0.28 alpha:1.0]; break; } @@ -84,12 +83,10 @@ static UIUserInterfaceStyle _userInterfaceStyle; [ThemeManager getUIStyle]; switch (self.userInterfaceStyle) { case UIUserInterfaceStyleLight: - NSLog(@"themeLightTX"); return [UIColor blackColor]; break; case UIUserInterfaceStyleDark: default: - NSLog(@"themeDarkTX"); return [UIColor whiteColor]; break; } @@ -100,7 +97,7 @@ static UIUserInterfaceStyle _userInterfaceStyle; } + (UIColor *)appSecondaryColor { - return [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0]; // 可换其他常用色 + return [UIColor colorWithRed:0.0 green:0.319 blue:0.64 alpha:1.0]; // 可换其他常用色 } + (UIColor *)appPrimaryColorWithAlpha { diff --git a/Limelight/UIAppView.m b/Limelight/UIAppView.m index 961d79c4..3b966571 100644 --- a/Limelight/UIAppView.m +++ b/Limelight/UIAppView.m @@ -142,7 +142,6 @@ static UIImage* noImage; if (appImage != nil) { // This size of image might be blank image received from GameStream. - //AppImage TESTTTTTTTT // TODO: Improve no-app image detection if (!(appImage.size.width == 130.f && appImage.size.height == 180.f) && // GFE 2.0 !(appImage.size.width == 628.f && appImage.size.height == 888.f)){ diff --git a/Limelight/ViewControllers/HostCollectionViewController.m b/Limelight/ViewControllers/HostCollectionViewController.m index c7b8fa47..61fad01e 100644 --- a/Limelight/ViewControllers/HostCollectionViewController.m +++ b/Limelight/ViewControllers/HostCollectionViewController.m @@ -73,11 +73,21 @@ static const CGFloat cellOffsetY = 20; @implementation HostCollectionViewController{ UICollectionViewFlowLayout *layout; + CGFloat _horizontalPadding; } - (instancetype)init { layout = [[UICollectionViewFlowLayout alloc] init]; - layout.sectionInset = UIEdgeInsetsMake(7, 0, 0, 0); // 上、左、下、右的间距 + switch ([UIDevice currentDevice].userInterfaceIdiom) { + case UIUserInterfaceIdiomPhone: + _horizontalPadding = 5; + break; + case UIUserInterfaceIdiomPad: + default: + _horizontalPadding = 75; + break; + } + layout.sectionInset = UIEdgeInsetsMake(7, _horizontalPadding, 0, _horizontalPadding); // 上、左、下、右的间距 if (self = [super initWithCollectionViewLayout:layout]) { _interItemMinimumSpacing = 10; _minimumLineSpacing = 10; @@ -177,9 +187,9 @@ static const CGFloat cellOffsetY = 20; _collectionViewHeightConstraint.constant = contentHeight; } - if([self numberOfRowsInCollectionView]<=2 && !contentExceedsView) layout.sectionInset = UIEdgeInsetsMake(50, 0, 0, 0); - if([self numberOfRowsInCollectionView]>2 && !contentExceedsView) layout.sectionInset = UIEdgeInsetsMake(25, 0, 0, 0); - if(contentExceedsView) layout.sectionInset = UIEdgeInsetsMake(7, 0, 0, 0); + if([self numberOfRowsInCollectionView]<=2 && !contentExceedsView) layout.sectionInset = UIEdgeInsetsMake(50, _horizontalPadding, 0, _horizontalPadding); + if([self numberOfRowsInCollectionView]>2 && !contentExceedsView) layout.sectionInset = UIEdgeInsetsMake(25, _horizontalPadding, 0, _horizontalPadding); + if(contentExceedsView) layout.sectionInset = UIEdgeInsetsMake(7, _horizontalPadding, 0, _horizontalPadding); } #pragma mark - UICollectionView DataSource diff --git a/Limelight/ViewControllers/MainFrameViewController.h b/Limelight/ViewControllers/MainFrameViewController.h index 56956aed..5ef880e5 100644 --- a/Limelight/ViewControllers/MainFrameViewController.h +++ b/Limelight/ViewControllers/MainFrameViewController.h @@ -25,7 +25,6 @@ @property (weak, nonatomic) IBOutlet UIBarButtonItem *settingsButton; #if !TARGET_OS_TV -@property (weak, nonatomic) IBOutlet UIBarButtonItem *upButton; @property (nonatomic, assign) bool settingsExpandedInStreamView; @property (nonatomic, strong) HostCollectionViewController *hostCollectionVC; @property (weak, nonatomic) IBOutlet UINavigationItem *navigationItem; diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index 1eb6eedb..4e7fd61e 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -48,8 +48,10 @@ @implementation MainFrameViewController { UILabel* waterMark; - UIBarButtonItem* addHostButton; - UIBarButtonItem* helpButton; + UIBarButtonItem* _addHostButton; + UIBarButtonItem* _helpButton; + UIBarButtonItem* _upButton; + UILabel* hostViewTitleLabel; //CGFloat recordedScreenWidth; NSOperationQueue* _opQueue; @@ -66,6 +68,9 @@ NSArray* _sortedAppList; NSCache* _boxArtCache; bool _background; + UINavigationBarAppearance *navBarAppearanceStandard; + UINavigationBarAppearance *navBarAppearanceScroll; + #if TARGET_OS_TV UITapGestureRecognizer* _menuRecognizer; #endif @@ -131,10 +136,12 @@ static NSMutableSet* hostList; - (void)updateTitle { - self.navigationController.navigationBar.titleTextAttributes = @{ - NSFontAttributeName: [UIFont systemFontOfSize:20 weight:UIFontWeightMedium], - NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 - }; + if (@available(iOS 13.0, *)) { + navBarAppearanceScroll.titleTextAttributes = navBarAppearanceStandard.titleTextAttributes = @{ + NSFontAttributeName: [UIFont systemFontOfSize:20 weight:UIFontWeightMedium], + NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 + }; + } if (_selectedHost != nil) { self.title = _selectedHost.name; @@ -144,13 +151,25 @@ static NSMutableSet* hostList; self.title = [LocalizationHelper localizedStringForKey: @"Searching for PCs on your network..."] ; } else { + if (@available(iOS 13.0, *)) { + navBarAppearanceScroll.titleTextAttributes = navBarAppearanceStandard.titleTextAttributes = @{ + NSFontAttributeName: [UIFont systemFontOfSize:24 weight:UIFontWeightSemibold], + NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 + }; + } + /* self.navigationController.navigationBar.titleTextAttributes = @{ NSFontAttributeName: [UIFont systemFontOfSize:24 weight:UIFontWeightSemibold], NSForegroundColorAttributeName: [ThemeManager textColor] // 可选,设置标题颜色 - }; + };*/ self.title = [LocalizationHelper localizedStringForKey: @"Hosts" ]; //self.title = nil; } + if (@available(iOS 13.0, *)) { + [self applyNavBarAppearance]; + } else { + // Fallback on earlier versions + } } - (void)alreadyPaired { @@ -311,10 +330,11 @@ static NSMutableSet* hostList; _selectedHost = nil; _sortedAppList = nil; - [self.collectionView removeFromSuperview]; // necessary for new scroll host view reloading mechanism + // [self.collectionView removeFromSuperview]; // necessary for new scroll host view reloading mechanism + self.hostCollectionVC.view.hidden = NO; + self.collectionView.hidden = YES; [self updateTitle]; - self.navigationItem.rightBarButtonItems = @[helpButton, addHostButton]; - [self->_upButton setTitle:nil]; + self.navigationItem.rightBarButtonItems = @[_helpButton, _addHostButton]; self.revealViewController.mainFrameIsInHostView = true; // to allow orientation change only in app view, tell top view controller the mainframe is not in host view } @@ -341,14 +361,19 @@ static NSMutableSet* hostList; //_appManager = [[AppAssetManager alloc] initWithCallback:self]; [self.collectionView setCollectionViewLayout:self.collectionViewLayout]; [self.collectionView reloadData]; //for new scroll host view reloading mechanism - [self.view addSubview:self.collectionView]; //for new scroll host view reloading mechanism + // [self.view bringSubviewToFront:self.collectionView]; + self.hostCollectionVC.view.hidden = YES; + self.collectionView.hidden = NO; + self.collectionView.backgroundColor = [ThemeManager appBackgroundColor]; [self attachWaterMark]; - [self->_upButton setTitle: [LocalizationHelper localizedStringForKey: @"Select New Host"]]; self.navigationItem.rightBarButtonItems = @[_upButton]; self.revealViewController.mainFrameIsInHostView = false; // [self disableNavigation]; [self updateTitle]; [self alreadyPaired]; + // self.navigationController.navigationBar.backgroundColor = [ThemeManager appBackgroundColor]; + // self.navigationController.navigationBar.translucent = NO; + //[self applyNavBarAppearance:navBarAppearance]; } - (void)appButtonTappedForHost:(TemporaryHost *)host { @@ -1038,12 +1063,6 @@ static NSMutableSet* hostList; } #if !TARGET_OS_TV -// this method is deprecated -- (void)simulateSettingsButtonPressClose { //force expand settings view to update resolution table, and all setting includes current fullscreen resolution will be updated. - if (currentPosition == FrontViewPositionRight && _settingsButton.target && [_settingsButton.target respondsToSelector:_settingsButton.action]) { - [_settingsButton.target performSelector:_settingsButton.action withObject:_settingsButton]; - } -} - (void)simulateSettingsButtonPress { //simulate pressing the setting button, called from setting view controller. //if([self isIPhonePortrait]) return; // disable settings view expanding in iphone portrait mode since it's buggy. @@ -1053,15 +1072,15 @@ static NSMutableSet* hostList; } - (void)handleOrientationChange { - UIDeviceOrientation targetOrientation = [[UIDevice currentDevice] orientation]; - if([self isIPhone] && UIDeviceOrientationIsPortrait(targetOrientation)) [self simulateSettingsButtonPressClose]; // on iphone, force close settings views if target orietation is portrait. + // UIDeviceOrientation targetOrientation = [[UIDevice currentDevice] orientation]; + // if([self isIPhone] && UIDeviceOrientationIsPortrait(targetOrientation)) [self simulateSettingsButtonPressClose]; // on iphone, force close settings views if target orietation is portrait. double delayInSeconds = 0.7; // Convert the delay into a dispatch_time_t value dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); // Perform some task after the delay dispatch_after(delayTime, dispatch_get_main_queue(), ^{// Code to execute after the delay // [self updateResolutionAccordingly]; - [self.settingsButton setEnabled:![self isIPhonePortrait]]; //make sure settings button is disabled in iphone portrait mode. + // [self.settingsButton setEnabled:![self isIPhonePortrait]]; //make sure settings button is disabled in iphone portrait mode. }); } @@ -1075,23 +1094,21 @@ static NSMutableSet* hostList; } - (void)revealController:(SWRevealViewController *)revealController willMoveToPosition:(FrontViewPosition)position { - + SettingsViewController* settingsViewController = (SettingsViewController*)[revealController rearViewController]; + if (position == FrontViewPositionLeft) { self.navigationItem.leftBarButtonItems = @[_settingsButton]; } else { self.navigationItem.leftBarButtonItems = @[]; + [settingsViewController updateTheme]; } - SettingsViewController* settingsViewController = (SettingsViewController*)[revealController rearViewController]; settingsViewController.mainFrameViewController = self; // enable / disable widgets acoordingly: in streamview, disable, outside of streamview, enable. - if (@available(iOS 16.0, *)) { - revealController.disconnectButton.hidden = !self.settingsExpandedInStreamView; - } else { - revealController.disconnectButton.enabled = self.settingsExpandedInStreamView; - // Fallback on earlier versions - } + if(self.settingsExpandedInStreamView) [revealController buttonsInStreaming]; + else [revealController buttonsNotInStreaming]; + [settingsViewController.resolutionSelector setEnabled:!self.settingsExpandedInStreamView]; settingsViewController.resolutionStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.framerateSelector setEnabled:!self.settingsExpandedInStreamView]; @@ -1351,19 +1368,47 @@ static NSMutableSet* hostList; ]]; } +- (void)applyNavBarAppearance API_AVAILABLE(ios(13.0)){ + self.navigationController.navigationBar.standardAppearance = navBarAppearanceStandard; + self.navigationController.navigationBar.scrollEdgeAppearance = navBarAppearanceStandard; +} - (void)setupNavBar{ + if (@available(iOS 13.0, *)) { + navBarAppearanceStandard = [[UINavigationBarAppearance alloc] init]; + [navBarAppearanceStandard configureWithOpaqueBackground]; // 不透明 + navBarAppearanceStandard.backgroundColor =[ThemeManager appBackgroundColor];; // 设置你需要的背景色 + navBarAppearanceStandard.shadowColor = nil; // 去掉底部分割线(可选) + navBarAppearanceStandard.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;*/ + + //appearance. + [self applyNavBarAppearance]; + } - self->addHostButton = [self createAddHostButton]; - self->helpButton = [self createHelpButton]; + self->_addHostButton = [self createAddHostButton]; + self->_helpButton = [self createHelpButton]; //[self setupHostViewTitle]; - self.navigationItem.rightBarButtonItems = @[helpButton, addHostButton]; // 顺序:右边靠右的是第一个 + + + + self.navigationItem.rightBarButtonItems = @[_helpButton, _addHostButton]; // 顺序:右边靠右的是第一个 - self.navigationController.navigationBar.backgroundColor = [ThemeManager appBackgroundColor]; - // self.navigationController.navigationBar - self.navigationController.navigationBar.titleTextAttributes = @{ - NSForegroundColorAttributeName: [ThemeManager textColor] - }; // Set the side bar button action. When it's tapped, it'll show the sidebar. [_settingsButton setTarget:self.revealViewController]; @@ -1379,6 +1424,8 @@ static NSMutableSet* hostList; } // Set the host name button action. When it's tapped, it'll show the host selection view. + _upButton = [[UIBarButtonItem alloc] init]; + [self->_upButton setTitle: [LocalizationHelper localizedStringForKey: @"Select New Host"]]; [_upButton setTarget:self]; [_upButton setAction:@selector(switchToHostView)]; } @@ -1387,8 +1434,12 @@ static NSMutableSet* hostList; [ThemeManager setUserInterfaceStyle:UIUserInterfaceStyleUnspecified]; [super viewDidLoad]; //[OrientationHelper updateOrientationToLandscape]; - - + // self.navigationController.delegate = self; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(deviceOrientationDidChange) // handle orientation change since i made portrait mode available + name:UIDeviceOrientationDidChangeNotification + object:nil]; + #if !TARGET_OS_TV self.settingsExpandedInStreamView = false; // init this flag self.revealViewController.isStreaming = false; //init this flag for rvlVC @@ -1484,7 +1535,6 @@ static NSMutableSet* hostList; -(void)viewDidLayoutSubviews{ [super viewDidLayoutSubviews]; - [self updateHosts]; } @@ -1653,16 +1703,16 @@ static NSMutableSet* hostList; [[self revealViewController] setPrimaryViewController:self]; self.revealViewController.isStreaming = false; // tell the revealViewController streaming is finished - [self.settingsButton setEnabled:![self isIPhonePortrait]]; //make sure settings button is disabled in iphone portrait mode. + //[self.settingsButton setEnabled:![self isIPhonePortrait]]; //make sure settings button is disabled in iphone portrait mode. //recordedScreenWidth = CGRectGetWidth([[UIScreen mainScreen] bounds]); // Get the screen's bounds (in points), update recorded screen width #endif - [self.navigationController setNavigationBarHidden:NO animated:YES]; + [self.navigationController setNavigationBarHidden:NO animated:NO]; // Hide 1px border line UIImage* fakeImage = [[UIImage alloc] init]; - [self.navigationController.navigationBar setShadowImage:fakeImage]; - [self.navigationController.navigationBar setBackgroundImage:fakeImage forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault]; + // [self.navigationController.navigationBar setShadowImage:fakeImage]; + // [self.navigationController.navigationBar setBackgroundImage:fakeImage forBarPosition:UIBarPositionAny barMetrics:UIBarMetricsDefault]; // Check for a pending shortcut action when appearing [self handlePendingShortcutAction]; @@ -1707,8 +1757,9 @@ static NSMutableSet* hostList; // for that which would normally fire beginForegroundRefresh. self.view.backgroundColor = [ThemeManager appBackgroundColor]; - + [self.view addSubview:self.collectionView]; [self initHostCollection]; + [self switchToHostView]; [self retrieveSavedHosts]; @@ -1799,7 +1850,6 @@ static NSMutableSet* hostList; - (void)updateHosts { Log(LOG_I, @"Updating hosts..."); - float prevEdge = -1; @synchronized (hostList) { // Sort the host list in alphabetical order NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)]; @@ -1844,6 +1894,18 @@ static NSMutableSet* hostList; // This function forces immediate decoding of the UIImage, rather // than the default lazy decoding that results in janky scrolling. +-(void)deviceOrientationDidChange{ + if(self.collectionView.superview == nil) return; + [NSLayoutConstraint activateConstraints:@[ + [self.collectionView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], + [self.collectionView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], + [self.collectionView.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor], + [self.collectionView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor], + //[self.collectionView.heightAnchor constraintEqualToConstant:_headerViewHeight] + ]]; +} + + + (UIImage*) loadBoxArtForCaching:(TemporaryApp*)app { UIImage* boxArt; @@ -1925,7 +1987,7 @@ static NSMutableSet* hostList; [cell.subviews.firstObject removeFromSuperview]; // Remove a view that was previously added [cell addSubview:appView]; - [self.settingsButton setEnabled:![self isIPhonePortrait]]; // update settings button after host is clicked & appview loaded + // [self.settingsButton setEnabled:![self isIPhonePortrait]]; // update settings button after host is clicked & appview loaded // Shadow opacity is controlled inside UIAppView based on whether the app // is hidden or not during the update cycle. UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:cell.bounds]; @@ -2008,7 +2070,8 @@ static NSMutableSet* hostList; - (CGSize)getHostCardSize{ CGSize cardSize; - cardSize.height = 0.25*MIN(CGRectGetHeight([[UIScreen mainScreen] bounds]),CGRectGetWidth([[UIScreen mainScreen] bounds])); + if([self isIPhone]) cardSize.height = 0.4*MIN(CGRectGetHeight([[UIScreen mainScreen] bounds]),CGRectGetWidth([[UIScreen mainScreen] bounds])); + else cardSize.height = 0.25*MIN(CGRectGetHeight([[UIScreen mainScreen] bounds]),CGRectGetWidth([[UIScreen mainScreen] bounds])); TemporaryHost* dummyHost = [[TemporaryHost alloc] init]; HostCardView* dummyCard = [[HostCardView alloc] initWithHost:dummyHost]; cardSize.width = cardSize.height * (dummyCard.size.width/dummyCard.size.height); @@ -2027,12 +2090,12 @@ static NSMutableSet* hostList; [self.view addSubview:self.hostCollectionVC.view]; // 设置其布局(Auto Layout 示例) - CGFloat hostCollectionViewPadding = 75; + // CGFloat hostCollectionViewPadding = 75; self.hostCollectionVC.view.translatesAutoresizingMaskIntoConstraints = NO; [NSLayoutConstraint activateConstraints:@[ [self.hostCollectionVC.view.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor constant:0], - [self.hostCollectionVC.view.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor constant:hostCollectionViewPadding], - [self.hostCollectionVC.view.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor constant:-hostCollectionViewPadding], + [self.hostCollectionVC.view.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor constant:0], + [self.hostCollectionVC.view.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor constant:0], // [self.hostCollectionVC.view.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:0] //? ]]; @@ -2041,5 +2104,4 @@ static NSMutableSet* hostList; } - @end diff --git a/Limelight/ViewControllers/SWRevealViewController.h b/Limelight/ViewControllers/SWRevealViewController.h index 00087dad..679dad0c 100755 --- a/Limelight/ViewControllers/SWRevealViewController.h +++ b/Limelight/ViewControllers/SWRevealViewController.h @@ -241,7 +241,8 @@ typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType) /* The following properties are provided for further customization, they are set to default values on initialization, you do not generally have to set them */ -@property (strong, nonatomic) UIBarButtonItem *disconnectButton; +@property (nonatomic, strong) UIBarButtonItem* disconnectButton; +@property (nonatomic, strong) UIBarButtonItem* moreButton; // Defines how much of the rear or right view is shown, default is 260. // Negative values indicate that the reveal width should be computed by substracting the full front view width, @@ -321,6 +322,10 @@ typedef NS_ENUM(NSInteger, SWRevealToggleAnimationType) @property (nonatomic,assign) bool isStreaming; @property (nonatomic,assign) bool mainFrameIsInHostView; +- (void)buttonsInStreaming; +- (void)buttonsNotInStreaming; + + @end diff --git a/Limelight/ViewControllers/SWRevealViewController.m b/Limelight/ViewControllers/SWRevealViewController.m index 0e00c275..6f025e3c 100755 --- a/Limelight/ViewControllers/SWRevealViewController.m +++ b/Limelight/ViewControllers/SWRevealViewController.m @@ -32,6 +32,7 @@ #import "SWRevealViewController.h" #import "LocalizationHelper.h" #import "DataManager.h" +#import "ThemeManager.h" #pragma mark - StatusBar Helper Function @@ -76,10 +77,12 @@ static CGFloat statusBarAdjustment( UIView* view ) @implementation SWRevealView{ - + UIView *_safeAreaPadding; + UIView* _separatorLine; } + static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1, CGFloat max1) { CGFloat result = min2 + (v1-min1)*((max2-min2)/(max1-min1)); @@ -107,6 +110,7 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1 [self setupRearNavView]; } + return self; } @@ -138,8 +142,11 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1 - (void)setupRearNavView { // 初始化 rearNavView _rearNavView = [[UIView alloc] init]; + _safeAreaPadding = [[UIView alloc] init]; _rearNavView.translatesAutoresizingMaskIntoConstraints = NO; - _rearNavView.backgroundColor = [UIColor lightGrayColor]; // 设置背景色以便查看 + _safeAreaPadding.translatesAutoresizingMaskIntoConstraints = NO; + // _rearNavView.backgroundColor = [UIColor lightGrayColor]; // 设置背景色以便查看 + _safeAreaPadding.backgroundColor = [ThemeManager appBackgroundColor]; // NSLog(@"_c.rearViewRevealWidth: %f", _c.rearViewRevealWidth); // _rearNavView.frame = CGRectMake(0, 0, _c.rearViewRevealWidth, 100); @@ -148,17 +155,19 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1 // 设置约束 - 这里只是一个示例,你可以根据需要调整 [self insertSubview:_rearNavView belowSubview:_frontView]; - + [self insertSubview:_safeAreaPadding belowSubview:_frontView]; + CGFloat navBarHeight = [UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPhone ? UINavigationBarHeightIPhone : UINavigationBarHeightIPad; [NSLayoutConstraint activateConstraints:@[ - [_rearNavView.topAnchor constraintEqualToAnchor:self.topAnchor], + [_rearNavView.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor constant:navBarHeight], [_rearNavView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], [_rearNavView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], [_rearNavView.heightAnchor constraintEqualToConstant:navBarHeight] // reserve height for navigation bar ]]; // [self setupNavigationBar]; + } - (void)prepareRearViewForPosition:(FrontViewPosition)newPosition @@ -250,6 +259,17 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1 UIBezierPath *shadowPath = [UIBezierPath bezierPathWithRect:shadowBounds]; _frontView.layer.shadowPath = shadowPath.CGPath; + + _safeAreaPadding.hidden = self.safeAreaLayoutGuide.topAnchor == 0; + [NSLayoutConstraint activateConstraints:@[ + [_safeAreaPadding.bottomAnchor constraintEqualToAnchor:self.safeAreaLayoutGuide.topAnchor constant:0], + [_safeAreaPadding.topAnchor constraintEqualToAnchor:self.topAnchor], + [_safeAreaPadding.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], + [_safeAreaPadding.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + // reserve height for navigation bar + ]]; + + //NSLog(@"width %f", self.bounds.size.width } @@ -619,6 +639,8 @@ static CGFloat scaledValue( CGFloat v1, CGFloat min2, CGFloat max2, CGFloat min1 @implementation SWRevealViewController { FrontViewPosition _panInitialFrontPosition; + UINavigationItem *_navItem; + UIView* _separatorLine; NSMutableArray *_animationQueue; BOOL _userInteractionStore; UIViewController *_primaryViewController; @@ -666,6 +688,7 @@ const int FrontViewPositionNone = 0xff; _rearViewPosition = FrontViewPositionLeft; _rightViewPosition = FrontViewPositionLeft; _rearViewRevealWidth = 492.0f; + _rearViewRevealWidth = 400; // _rearViewRevealOverdraw = 60.0f; _rearViewRevealOverdraw = 0.0f; _rearViewRevealDisplacement = 40.0f; @@ -682,9 +705,11 @@ const int FrontViewPositionNone = 0xff; _toggleAnimationType = SWRevealToggleAnimationTypeSpring; _springDampingRatio = 1; _replaceViewAnimationDuration = 0.25; + // _frontViewShadowRadius = 2.5f; _frontViewShadowRadius = 2.5f; - _frontViewShadowOffset = CGSizeMake(0.0f, 2.5f); - _frontViewShadowOpacity = 1.0f; + //_frontViewShadowOffset = CGSizeMake(0.0f, 2.5f); + _frontViewShadowOffset = CGSizeMake(0, 0); + _frontViewShadowOpacity = 0; _frontViewShadowColor = [UIColor blackColor]; _userInteractionStore = YES; _animationQueue = [NSMutableArray array]; @@ -736,7 +761,6 @@ const int FrontViewPositionNone = 0xff; _contentView = [[SWRevealView alloc] initWithFrame:frame controller:self]; [self setupNavigationBar]; - // set the content view to resize along with its superview [_contentView setAutoresizingMask:UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight]; @@ -758,6 +782,8 @@ const int FrontViewPositionNone = 0xff; // now set the desired initial position [self _setFrontViewPosition:initialPosition withDuration:0.0]; + [self setupMenuSeparator]; + } - (bool)isIphone{ @@ -775,9 +801,9 @@ const int FrontViewPositionNone = 0xff; // tested on iOS17. - (UIInterfaceOrientationMask)supportedInterfaceOrientations { // Return the supported interface orientations acoordingly - if(self.mainFrameIsInHostView){ - if([self isIphone]) return UIInterfaceOrientationMaskLandscape; //always try to lock orientaion to landscape in mainFrameView in order to prevent bug. - else return [self getCurrentOrientation]; //always try to lock current orientaion in mainFrameView for iPad in order to prevent bug. + if(!_isStreaming){ + if([self isIphone]) return UIInterfaceOrientationMaskAll; //always try to lock orientaion to landscape in mainFrameView. + else return UIInterfaceOrientationMaskAll; //always try to lock current orientaion in mainFrameView for iPad in order to prevent bug. } //lock the orientation accordingly after streaming is started @@ -794,6 +820,15 @@ const int FrontViewPositionNone = 0xff; // [self setupNavigationBarConstraints]; } +- (void)viewSafeAreaInsetsDidChange { + [super viewSafeAreaInsetsDidChange]; + +} + +- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { + +} + - (void)viewDidLoad{ self.isStreaming = false; //init this flag @@ -825,46 +860,71 @@ const int FrontViewPositionNone = 0xff; #pragma mark - Public methods and property accessors +- (void)willMoveToPosition{ + _separatorLine.hidden = _frontViewPosition == FrontViewPositionLeft; +} + + +- (void)setupMenuSeparator{ + // 分隔线 + _separatorLine = [[UIView alloc] init]; + _separatorLine.backgroundColor = [ThemeManager separatorColor]; + _separatorLine.translatesAutoresizingMaskIntoConstraints = NO; + [_contentView.frontView addSubview:_separatorLine]; + _separatorLine.hidden = YES; + /* + [NSLayoutConstraint activateConstraints:@[ + [_separatorLine.trailingAnchor constraintEqualToAnchor:self.centerXAnchor constant:-10], + [_separatorLine.topAnchor constraintEqualToAnchor:self.topAnchor], + [_separatorLine.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + [_separatorLine.widthAnchor constraintEqualToConstant:1.0] + ]]; + */ + [NSLayoutConstraint activateConstraints:@[ + [_separatorLine.topAnchor constraintEqualToAnchor:_contentView.topAnchor constant:0], + + [_separatorLine.bottomAnchor constraintEqualToAnchor:_contentView.bottomAnchor constant:0], + //[_separatorLine.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:self.bounds.size.width-60], + [_separatorLine.leadingAnchor constraintEqualToAnchor:_contentView.frontView.leadingAnchor constant:5], + [_separatorLine.trailingAnchor constraintEqualToAnchor:_contentView.frontView.leadingAnchor constant:6.5], + ]]; +} + + - (void)setupNavigationBar { // 创建导航栏 if (_dockedNavBar == nil) _dockedNavBar = [[UINavigationBar alloc] init]; _dockedNavBar.translatesAutoresizingMaskIntoConstraints = NO; _dockedNavBar.userInteractionEnabled = YES; - // 创建导航项 - UINavigationItem *navItem = [[UINavigationItem alloc] initWithTitle:[LocalizationHelper localizedStringForKey:@"Settings"]]; - - // Back Button - - UIButton *customBackButton = [UIButton buttonWithType:UIButtonTypeSystem]; if (@available(iOS 13.0, *)) { - [customBackButton setImage:[UIImage systemImageNamed:@"chevron.left"] forState:UIControlStateNormal]; + UINavigationBarAppearance *navBarAppearanceStandard = [[UINavigationBarAppearance alloc] init]; + [navBarAppearanceStandard configureWithOpaqueBackground]; // 不透明 + navBarAppearanceStandard.backgroundColor =[ThemeManager appBackgroundColor];; // 设置你需要的背景色 + navBarAppearanceStandard.shadowColor = nil; // 去掉底部分割线(可选) + navBarAppearanceStandard.titleTextAttributes = @{ + NSForegroundColorAttributeName: [ThemeManager textColor] + }; + navBarAppearanceStandard.shadowColor = [UIColor clearColor]; + navBarAppearanceStandard.backgroundImage = nil; + _dockedNavBar.standardAppearance = navBarAppearanceStandard; + _dockedNavBar.scrollEdgeAppearance = navBarAppearanceStandard; } else { - // Fallback on earlier versions + _dockedNavBar.backgroundColor = [ThemeManager appBackgroundColor]; } - [customBackButton setTitle:[LocalizationHelper localizedStringForKey:@"Back"] forState:UIControlStateNormal]; - customBackButton.titleLabel.font = [UIFont systemFontOfSize:19 weight:UIFontWeightRegular]; - [customBackButton addTarget:self action:@selector(foldRearView) forControlEvents:UIControlEventTouchUpInside]; - //customBackButton.contentEdgeInsets = UIEdgeInsetsMake(8, 8, 8, 8); // 增加点击区域 - // customBackButton.titleEdgeInsets = UIEdgeInsetsMake(0, 5, 0, -5); - UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithCustomView:customBackButton]; - - /* - UIBarButtonItem *backButtonItem = [[UIBarButtonItem alloc] initWithTitle:[LocalizationHelper localizedStringForKey:@"Back"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(foldRearView)]; - */ + - navItem.leftBarButtonItem = backButtonItem; + // 创建导航项 + _navItem = [[UINavigationItem alloc] initWithTitle:[LocalizationHelper localizedStringForKey:@"Settings"]]; - _disconnectButton = [[UIBarButtonItem alloc] initWithTitle:[LocalizationHelper localizedStringForKey:@"Disconnect"] - style:UIBarButtonItemStylePlain - target:self - action:@selector(disconnectRemoteSession)]; - navItem.rightBarButtonItem = _disconnectButton; - [_dockedNavBar setItems:@[navItem]]; + [self setupBackButton]; + [self setupDisconnectButton]; + [self setupMoreButton]; + + // navItem.rightBarButtonItem = _disconnectButton; + + [_dockedNavBar setItems:@[_navItem]]; _dockedNavBar.barTintColor = [UIColor darkGrayColor]; _dockedNavBar.titleTextAttributes = @{NSForegroundColorAttributeName: [UIColor whiteColor]}; @@ -877,9 +937,132 @@ const int FrontViewPositionNone = 0xff; [_dockedNavBar.leadingAnchor constraintEqualToAnchor:_contentView.rearNavView.leadingAnchor], [_dockedNavBar.widthAnchor constraintEqualToConstant:_rearViewRevealWidth], ]]; + NSLog(@"rearViewRevealWidth %f", _rearViewRevealWidth); } + +- (void)setupBackButton{ + // Back Button + UIBarButtonItem *backButton = [[UIBarButtonItem alloc] init]; + [backButton setTarget:self]; + [backButton setAction:@selector(foldRearView)]; + 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]; + [backButton setImage:image]; + backButton.imageInsets = UIEdgeInsetsMake(20, 10, 0, 0); + } else { + [backButton setTitle:[LocalizationHelper localizedStringForKey:@"Back"]]; + } + _navItem.leftBarButtonItem = backButton; +} + +- (void)setupDisconnectButton{ + // disconnect button + + _disconnectButton = [[UIBarButtonItem alloc] init]; + [_disconnectButton setTarget:self]; + [_disconnectButton setAction:@selector(disconnectRemoteSession)]; + if (@available(iOS 13.0, *)) { + [_disconnectButton setTitle:nil]; + UIImage *image = [[UIImage imageNamed:@"disconnect.svg" ] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + + [_disconnectButton setImage:image]; + //_disconnectButton.imageInsets = UIEdgeInsetsMake(5, 5, 5, 5); + _disconnectButton.tintColor = [ThemeManager appPrimaryColor]; + } else { + [_disconnectButton setTitle:[LocalizationHelper localizedStringForKey:@"Disconnect"]]; + } + + /* + _disconnectButton = [[UIBarButtonItem alloc] initWithTitle:[LocalizationHelper localizedStringForKey:@"Disconnect"] + style:UIBarButtonItemStylePlain + target:self + action:@selector(disconnectRemoteSession)]; + */ +} + +- (void)setupMoreButton{ + _moreButton = [[UIBarButtonItem alloc] init]; + + //[moreButton setAction:@selector(moreButtonTapped:)]; + 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]; + [_moreButton setImage:image]; + _moreButton.imageInsets = UIEdgeInsetsMake(20, 0, 0, -10); + } else { + [_moreButton setTitle:[LocalizationHelper localizedStringForKey:@"More"]]; + } + + if (@available(iOS 14.0, *)) { + UIAction *action1 = [UIAction actionWithTitle:@"操作1" image:[UIImage systemImageNamed:@"doc"] identifier:nil handler:^(__kindof UIAction * _Nonnull action) { + NSLog(@"执行操作1"); + }]; + + UIAction *action2 = [UIAction actionWithTitle:@"操作2" image:[UIImage systemImageNamed:@"folder"] identifier:nil handler:^(__kindof UIAction * _Nonnull action) { + NSLog(@"执行操作2"); + }]; + + UIAction *deleteAction = [UIAction actionWithTitle:@"删除" image:[UIImage systemImageNamed:@"trash"] identifier:nil handler:^(__kindof UIAction * _Nonnull action) { + NSLog(@"执行删除操作"); + }]; + deleteAction.attributes = UIMenuElementAttributesDestructive; + // 创建菜单 + UIMenu *menu = [UIMenu menuWithTitle:@"" children:@[action1, action2, deleteAction]]; + _moreButton.menu = menu; + } + else{ + [_moreButton setTarget:self]; + [_moreButton setAction:@selector(moreButtonTapped:)]; + } + // more option button +} + +- (void)moreButtonTapped:(UIBarButtonItem *)sender { + UIMenuItem *item1 = [[UIMenuItem alloc] initWithTitle:@"操作1" action:@selector(action1)]; + UIMenuItem *item2 = [[UIMenuItem alloc] initWithTitle:@"操作2" action:@selector(action2)]; + + UIMenuController *menuController = [UIMenuController sharedMenuController]; + [menuController setMenuItems:@[item1, item2]]; + + UIView *targetView = [sender valueForKey:@"view"]; + [menuController setTargetRect:targetView.bounds inView:targetView]; + [menuController setMenuVisible:YES animated:YES]; + + [self becomeFirstResponder]; +} + +- (BOOL)canBecomeFirstResponder { + return YES; +} + +- (BOOL)canPerformAction:(SEL)action withSender:(id)sender { + if (action == @selector(action1) || action == @selector(action2)) { + return YES; + } + return NO; +} + +- (void)action1 { + NSLog(@"执行操作1"); +} + +- (void)action2 { + NSLog(@"执行操作2"); +} + +- (void)buttonsInStreaming{ + _navItem.rightBarButtonItems = @[_disconnectButton]; +} + +- (void)buttonsNotInStreaming{ + _navItem.rightBarButtonItems = @[_moreButton]; +} + - (void)foldRearView{ [self revealToggleAnimated:YES]; } @@ -889,6 +1072,19 @@ const int FrontViewPositionNone = 0xff; [self foldRearView]; } +-(void)deviceOrientationDidChange{ + /* + if(self. == nil) return; + [NSLayoutConstraint activateConstraints:@[ + [self.collectionView.topAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.topAnchor], + [self.collectionView.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor], + [self.collectionView.leadingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.leadingAnchor], + [self.collectionView.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor], + //[self.collectionView.heightAnchor constraintEqualToConstant:_headerViewHeight] + ]]; + */ +} + - (void)setFrontViewController:(UIViewController *)frontViewController { [self setFrontViewController:frontViewController animated:NO]; @@ -1358,7 +1554,7 @@ const int FrontViewPositionNone = 0xff; - (void)_handleRevealGestureStateBeganWithRecognizer:(UIPanGestureRecognizer *)recognizer { // we know that we will not get here unless the animationQueue is empty because the recognizer - // delegate prevents it, however we do not want any forthcoming programatic actions to disturb + // delegate prevfents it, however we do not want any forthcoming programatic actions to disturb // the gesture, so we just enqueue a dummy block to ensure any programatic acctions will be // scheduled after the gesture is completed [self _enqueueBlock:^{}]; // <-- dummy block @@ -1697,6 +1893,7 @@ const int FrontViewPositionNone = 0xff; } _frontViewPosition = newPosition; + [self willMoveToPosition]; void (^deploymentCompletion)(void) = [self _deploymentForViewController:_frontViewController inView:_contentView.frontView appear:appear disappear:disappear]; @@ -1981,6 +2178,12 @@ const int FrontViewPositionNone = 0xff; return (id)parent; } +- (void)buttonsInStreaming { +} + +- (void)buttonsNotInStreaming { +} + @end diff --git a/Limelight/ViewControllers/SettingsViewController.h b/Limelight/ViewControllers/SettingsViewController.h index 82c136cd..8119a19c 100644 --- a/Limelight/ViewControllers/SettingsViewController.h +++ b/Limelight/ViewControllers/SettingsViewController.h @@ -104,9 +104,11 @@ #pragma clang diagnostic pop -- (void) saveSettings; -+ (bool) isLandscapeNow; +- (void)saveSettings; ++ (bool)isLandscapeNow; - (void)updateResolutionTable; -- (void) widget:(UISlider*)widget setEnabled:(bool)enabled; +- (void)widget:(UISlider*)widget setEnabled:(bool)enabled; +- (void)updateTheme; + @end diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index 156e6b1f..c3dc1ea9 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -13,6 +13,7 @@ #import "TemporarySettings.h" #import "DataManager.h" #import "MenuSectionView.h" +#import "ThemeManager.h" #import #import @@ -181,13 +182,37 @@ CGSize resolutionTable[RESOLUTION_TABLE_SIZE]; // Add a bit of padding so the view doesn't end right at the button of the display self.scrollView.contentSize = CGSizeMake(self.scrollView.contentSize.width, [self isIPhone] ? highestViewY + 20 : parentStack.frame.size.height + [self getStandardNavBarHeight] + 20); + /* + self.scrollView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + // [self.scrollView.topAnchor constraintEqualToAnchor:], + [self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [self.scrollView.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + ]]; + + NSLog(@"settingsViewWidth: %f", self.view.bounds.size.width); +*/ + + + + double delayInSeconds = 3; + // Convert the delay into a dispatch_time_t value + dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC)); + // Perform some task after the delay + dispatch_after(delayTime, dispatch_get_main_queue(), ^{// Code to execute after the delay + // [self updateResolutionAccordingly]; + }); + } // Adjust the subviews for the safe area on the iPhone X. - (void)viewSafeAreaInsetsDidChange { [super viewSafeAreaInsetsDidChange]; - if (@available(iOS 11.0, *)) { + //if (@available(iOS 11.0, *)) { + if (false) { // cancel this for portrait mode for (UIView* view in self.view.subviews) { // HACK: The official safe area is much too large for our purposes // so we'll just use the presence of any safe area to indicate we should @@ -276,6 +301,7 @@ BOOL isCustomResolution(CGSize res) { - (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; [self updateResolutionTable]; + //[self updateTheme]; NSLog(@"Resolution table updated"); } @@ -346,6 +372,19 @@ BOOL isCustomResolution(CGSize res) { self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic; // 可选:确保 scrollView 开启垂直滚动 self.scrollView.alwaysBounceVertical = YES; + self.scrollView.showsVerticalScrollIndicator = NO; + + /* + self.scrollView.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + // [self.scrollView.topAnchor constraintEqualToAnchor:], + [self.scrollView.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor], + [self.scrollView.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor], + [self.scrollView.topAnchor constraintEqualToAnchor:self.view.topAnchor], + [self.scrollView.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor], + ]]; + */ + parentStack = [[UIStackView alloc] init]; parentStack.axis = UILayoutConstraintAxisVertical; parentStack.spacing = 0; @@ -366,23 +405,34 @@ BOOL isCustomResolution(CGSize res) { if (@available(iOS 13.0, *)) { [videoSection setSectionIcon:[UIImage systemImageNamed:@"airplayvideo"]]; } else [videoSection setSectionIcon:nil]; + self.resolutionStack.accessibilityIdentifier = @"resolutionStack"; + self.fpsStack.accessibilityIdentifier = @"fpsStack"; + self.codecStack.accessibilityIdentifier = @"codecStack"; [videoSection addSubStackView:_resolutionStack]; [videoSection addSubStackView:_fpsStack]; [videoSection addSubStackView:_codecStack]; [videoSection addToParentStack:parentStack]; [videoSection setExpanded:YES]; + //_fpsStack.userInteractionEnabled = NO; MenuSectionView *gesturesSection = [[MenuSectionView alloc] init]; gesturesSection.sectionTitle = [LocalizationHelper localizedStringForKey:@"Gestures"]; if (@available(iOS 13.0, *)) { [gesturesSection setSectionIcon:[UIImage systemImageNamed:@"hand.draw"]]; } else [gesturesSection setSectionIcon:nil]; + self.keyboardToggleFingerNumStack.accessibilityIdentifier = @"keyboardToggleFingerNumStack"; + self.slideToSettingsScreenEdgeStack.accessibilityIdentifier = @"slideToSettingsScreenEdgeStack"; + self.slideToCmdToolScreenEdgeStack.accessibilityIdentifier = @"slideToCmdToolScreenEdgeStack"; + self.slideToSettingsDistanceStack.accessibilityIdentifier = @"slideToSettingsDistanceStack"; [gesturesSection addSubStackView:_keyboardToggleFingerNumStack]; [gesturesSection addSubStackView:_slideToSettingsScreenEdgeStack]; [gesturesSection addSubStackView:_slideToCmdToolScreenEdgeStack]; [gesturesSection addSubStackView:_slideToSettingsDistanceStack]; + // [gesturesSection addSubStackView:_unlockDisplayOrientationStack]; [gesturesSection addToParentStack:parentStack]; [gesturesSection setExpanded:YES]; + + } @@ -445,14 +495,39 @@ BOOL isCustomResolution(CGSize res) { [parentStackTmp removeFromSuperview]; } +- (void)handleLongPress:(UILongPressGestureRecognizer *)gesture { + if (gesture.state == UIGestureRecognizerStateBegan) { + CGPoint point = [gesture locationInView:self.view]; + UIView *touchedView = [self.view hitTest:point withEvent:nil]; + UIStackView* capturedStack; + if([touchedView isKindOfClass:[UIStackView class]]){ + if(touchedView.accessibilityIdentifier != nil) capturedStack = (UIStackView *)touchedView; + } + else if([touchedView.superview isKindOfClass:[UIStackView class]] && touchedView.superview.accessibilityIdentifier != nil) capturedStack = (UIStackView *)touchedView.superview; + else NSLog(@"hit test: not setting stack captured"); + // NSLog(@"hit test obj: %@", touchedView); + NSLog(@"hit test name: %@", capturedStack.accessibilityIdentifier); + } +} + - (void)viewDidLoad { + //[self updateTheme]; + + UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)]; + [self.view addGestureRecognizer:longPress]; + + // return; BOOL isIPad = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad); - if(isIPad) [self layoutWidgetes]; // layout for ipad tmply - - [self initParentStack]; - [self layoutSections]; - + if(isIPad){ + //[self layoutWidgetes]; // layout for ipad tmply + // [self.view ] + for(UIView* view in self.view.subviews){ + [view removeFromSuperview]; + } + [self initParentStack]; + [self layoutSections]; + } self->slideToCloseSettingsViewRecognizer = [[CustomEdgeSlideGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)]; @@ -1173,6 +1248,80 @@ BOOL isCustomResolution(CGSize res) { return resolutionTable[[self.resolutionSelector selectedSegmentIndex]].width; } +- (UIStackView *)findFlatStackViewFrom:(UIView *)view { + while (view != nil) { + if ([view isKindOfClass:[UIStackView class]]) { + UIStackView *stack = (UIStackView *)view; + BOOL hasNestedStack = NO; + for (UIView *sub in stack.arrangedSubviews) { + if ([sub isKindOfClass:[UIStackView class]]) { + hasNestedStack = YES; + break; + } + } + if (!hasNestedStack) { + return stack; + } + } + view = view.superview; + } + return nil; +} + + +- (void)updateThemeForLabels:(UIView *)view { + for (UIView *subview in view.subviews) { + if ([subview isKindOfClass:[UILabel class]]) { + UILabel *label = (UILabel *)subview; + if (@available(iOS 13.0, *)) { + label.layer.filters = nil; + label.textColor = [ThemeManager textColor]; + } else { + // Fallback on earlier versions + } + } + [self updateThemeForLabels:subview]; + } +} + +- (void)updateThemeForSelectors:(UIView *)view { + for (UIView *subview in view.subviews) { + if ([subview isKindOfClass:[UISegmentedControl class]]) { + UISegmentedControl *selector = (UISegmentedControl *)subview; + if (@available(iOS 13.0, *)) { + selector.selectedSegmentTintColor = [ThemeManager appSecondaryColor]; + } else { + // Fallback on earlier versions + } + } + [self updateThemeForSelectors:subview]; + } +} + +- (void)updateThemeForSliders:(UIView *)view { + for (UIView *subview in view.subviews) { + if ([subview isKindOfClass:[UISlider class]]) { + UISlider *slider = (UISlider *)subview; + if (@available(iOS 13.0, *)) { + } else { + // Fallback on earlier versions + } + slider.tintColor = [ThemeManager appSecondaryColor]; + + } + [self updateThemeForSliders:subview]; + } +} + + +- (void)updateTheme{ + self.view.backgroundColor = [ThemeManager appBackgroundColor]; + [self updateThemeForLabels:self.view]; + [self updateThemeForSelectors:self.view]; + [self updateThemeForSliders:self.view]; +} + + - (void) saveSettings { DataManager* dataMan = [[DataManager alloc] init]; NSInteger framerate = [self getChosenFrameRate]; diff --git a/Limelight/ViewControllers/StreamFrameViewController.m b/Limelight/ViewControllers/StreamFrameViewController.m index b4f1aa8d..8d0684d8 100644 --- a/Limelight/ViewControllers/StreamFrameViewController.m +++ b/Limelight/ViewControllers/StreamFrameViewController.m @@ -323,8 +323,6 @@ dispatch_resume(timer); - // 防止循环引用(虽然这里用__block已经足够) - __weak typeof(alert) weakAlert = alert; }