From 2679ba75afa307d690d7e7979a4d6d59ad0f29ba Mon Sep 17 00:00:00 2001 From: TrueZhuangjia Date: Sat, 17 May 2025 23:07:33 +0800 Subject: [PATCH] hide some settings in streaming --- Limelight/Base.lproj/iPad.storyboard | 6 +- Limelight/HostCardView.h | 28 + Limelight/HostCardView.m | 610 ++++++++++++++++++ Limelight/MenuSectionView.h | 33 + Limelight/MenuSectionView.m | 324 ++++++++++ Limelight/UIColor+Theme.h | 28 + Limelight/UIColor+Theme.m | 67 ++ .../ViewControllers/MainFrameViewController.m | 54 +- .../ViewControllers/SettingsViewController.m | 139 ++-- Limelight/main.m | 1 + Moonlight.xcodeproj/project.pbxproj | 38 +- 11 files changed, 1271 insertions(+), 57 deletions(-) create mode 100644 Limelight/HostCardView.h create mode 100644 Limelight/HostCardView.m create mode 100644 Limelight/MenuSectionView.h create mode 100644 Limelight/MenuSectionView.m create mode 100644 Limelight/UIColor+Theme.h create mode 100644 Limelight/UIColor+Theme.m diff --git a/Limelight/Base.lproj/iPad.storyboard b/Limelight/Base.lproj/iPad.storyboard index a8a34226..3b96e1da 100644 --- a/Limelight/Base.lproj/iPad.storyboard +++ b/Limelight/Base.lproj/iPad.storyboard @@ -14,7 +14,7 @@ - + @@ -1270,13 +1270,13 @@ ICAgICAgICAgICAgICA - + - + diff --git a/Limelight/HostCardView.h b/Limelight/HostCardView.h new file mode 100644 index 00000000..34928aa0 --- /dev/null +++ b/Limelight/HostCardView.h @@ -0,0 +1,28 @@ +// +// HostCardView.h +// Moonlight-ZWM +// +// Created by True砖家 on 5/18/25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + + +#import +#import "TemporaryHost.h" + +@protocol HostCallback + +- (void) hostClicked:(TemporaryHost*)host view:(UIView*)view; +- (void) hostLongClicked:(TemporaryHost*)host view:(UIView*)view; +- (void) addHostClicked; + +@end + +@interface HostCardView : UIView +@property (nonatomic, assign) CGFloat sizeFactor; + +- (void)resizeBySizeFactor:(CGFloat)factor; +- (id) initWithHost:(TemporaryHost*)host; + +@end + diff --git a/Limelight/HostCardView.m b/Limelight/HostCardView.m new file mode 100644 index 00000000..0ddd0e93 --- /dev/null +++ b/Limelight/HostCardView.m @@ -0,0 +1,610 @@ +// +// HostCardView.m +// Moonlight-ZWM +// +// Created by True砖家 on 5/18/25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + +#import "HostCardView.h" +#import "LocalizationHelper.h" +#import "UIColor+Theme.h" + +@interface HostCardView () + +@property (nonatomic, strong) UIView *iconBackgroundView; +@property (nonatomic, strong) UIImageView *hostIconView; +@property (nonatomic, strong) UILabel *hostNameLabel; +@property (nonatomic, strong) UIImageView *statusIcon; +@property (nonatomic, strong) UILabel *statusLabel; +@property (nonatomic, strong) UIButton *leftButton; +@property (nonatomic, strong) UIButton *rightButton; +@property (nonatomic, strong) UIButton *pairButton; +@property (nonatomic, strong) UIButton *settingsButton; +@property (nonatomic, strong) NSLayoutConstraint *widthConstraint; +@property (nonatomic, strong) NSLayoutConstraint *heightConstraint; +@property (nonatomic, strong) UIView *separatorLine; +@property (nonatomic, assign) CGFloat cardContentpadding; +@property (nonatomic, assign) UIUserInterfaceStyle userIterfaceStyle; + +@end + + +@implementation HostCardView { + TemporaryHost* _host; + id _callback; + UIActivityIndicatorView* _hostSpinner; + UIImageView* lockIconView; + CGFloat computerIconMonitorCenterYOffset; + CGFloat buttonHeight; + CGFloat iconAndButtonSpacing; + UIColor *defaultBlue; + UIColor *defaultGreen; + CAGradientLayer *backgroundLayer; + +} + +static const float REFRESH_CYCLE = 2.0f; + + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + self.sizeFactor = 1.0; // decisive factor assign + computerIconMonitorCenterYOffset = -3.3*_sizeFactor; + iconAndButtonSpacing = 37*_sizeFactor; + buttonHeight = 40*_sizeFactor; + defaultBlue = [UIColor appPrimaryColor]; + defaultGreen = [UIColor colorWithRed:52.0/255.0 green:199.0/255.0 blue:89.0/255.0 alpha:1.0]; + self.userIterfaceStyle = self.traitCollection.userInterfaceStyle; + self.userIterfaceStyle = UIUserInterfaceStyleLight; + [self createBackgroundLayer]; + [self setupUI]; + } + return self; +} + +- (id) initWithHost:(TemporaryHost*)host { + self = [self init]; + _host = host; + + // Use UIContextMenuInteraction on iOS 13.0+ and a standard UILongPressGestureRecognizer + // for tvOS devices and iOS prior to 13.0. + return self; +} + + + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + [self setupUI]; + } + return self; +} + +- (void)resizeBySizeFactor:(CGFloat)factor{ + [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; + self.sizeFactor = factor; + [self setupUI]; +} + +- (void)setupUI { + self.backgroundColor = [UIColor widgetBackgroundColorDark]; // theme + self.layer.cornerRadius = 16; + self.cardContentpadding = 13 * _sizeFactor; + self.clipsToBounds = YES; + self.translatesAutoresizingMaskIntoConstraints = NO; + CGFloat appButtonWidth = 100*_sizeFactor; + CGFloat launchButtonWidth = 120*_sizeFactor; + /* + NSLayoutConstraint *topAnchorConstraint; + topAnchorConstraint = [self.topAnchor constraintEqualToAnchor:self.superview.topAnchor constant:500]; + topAnchorConstraint.active = YES; +*/ + _heightConstraint = [self.heightAnchor constraintEqualToConstant:300]; + _heightConstraint.active = YES; + _widthConstraint = [self.widthAnchor constraintEqualToConstant:300]; + _widthConstraint.active = YES; + + + // 图标背景 + self.iconBackgroundView = [[UIView alloc] initWithFrame:CGRectMake(_cardContentpadding, _cardContentpadding, 80*_sizeFactor, 80*_sizeFactor)]; + self.iconBackgroundView.backgroundColor = defaultBlue; + self.iconBackgroundView.layer.cornerRadius = 20*_sizeFactor; + [self addSubview:self.iconBackgroundView]; + + // 图标图片 + self.hostIconView = [[UIImageView alloc] init]; + self.hostIconView.translatesAutoresizingMaskIntoConstraints = NO; + self.hostIconView.contentMode = UIViewContentModeScaleAspectFit; + if (@available(iOS 13.0, *)) { + self.hostIconView.image = [UIImage systemImageNamed:@"display"]; + } else { + self.hostIconView.image = [UIImage imageNamed:@"Computer"]; + [NSLayoutConstraint activateConstraints:@[ + [self.hostIconView.heightAnchor constraintEqualToConstant:57*_sizeFactor], + [self.hostIconView.widthAnchor constraintEqualToConstant:57*_sizeFactor], + ]]; + } + self.hostIconView.tintColor = [UIColor whiteColor]; + [self.iconBackgroundView addSubview:self.hostIconView]; + [NSLayoutConstraint activateConstraints:@[ + [self.hostIconView.centerXAnchor constraintEqualToAnchor:self.iconBackgroundView.centerXAnchor constant:0], + [self.hostIconView.centerYAnchor constraintEqualToAnchor:self.iconBackgroundView.centerYAnchor constant:0], + [self.hostIconView.heightAnchor constraintEqualToConstant:63*_sizeFactor], + [self.hostIconView.widthAnchor constraintEqualToConstant:63*_sizeFactor], + ]]; + // [self.iconBackgroundView layoutIfNeeded]; + // [self.iconImageView layoutIfNeeded]; + + //spinner + _hostSpinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; + _hostSpinner.userInteractionEnabled = NO; + _hostSpinner.translatesAutoresizingMaskIntoConstraints = NO; + _hostSpinner.hidesWhenStopped = YES; + [self.iconBackgroundView addSubview:_hostSpinner]; + [NSLayoutConstraint activateConstraints:@[ + [_hostSpinner.centerXAnchor constraintEqualToAnchor:self.iconBackgroundView.centerXAnchor constant:0], + [_hostSpinner.centerYAnchor constraintEqualToAnchor:self.iconBackgroundView.centerYAnchor constant:computerIconMonitorCenterYOffset], + ]]; + _hostSpinner.transform = CGAffineTransformMakeScale(_sizeFactor, _sizeFactor); + [_hostSpinner stopAnimating]; + // [_hostSpinner startAnimating]; + + + // lockIcon + lockIconView =[[UIImageView alloc] init]; + lockIconView.translatesAutoresizingMaskIntoConstraints = NO; + if (@available(iOS 13.0, *)) { + lockIconView.image = [UIImage systemImageNamed:@"lock.fill"]; + } else { + // lockIconView.image = [UIImage imageNamed:@"Computer"]; + } + lockIconView.tintColor = [UIColor whiteColor]; + [self.iconBackgroundView insertSubview:lockIconView aboveSubview:_iconBackgroundView]; + [NSLayoutConstraint activateConstraints:@[ + [lockIconView.centerXAnchor constraintEqualToAnchor:_iconBackgroundView.centerXAnchor constant:0], + [lockIconView.centerYAnchor constraintEqualToAnchor:_iconBackgroundView.centerYAnchor constant:computerIconMonitorCenterYOffset], + [lockIconView.widthAnchor constraintEqualToConstant:22*_sizeFactor], + [lockIconView.heightAnchor constraintEqualToConstant:22*_sizeFactor] + ]]; + lockIconView.hidden = true; + + // 设备名 + self.hostNameLabel = [[UILabel alloc] initWithFrame:CGRectMake(_cardContentpadding+_iconBackgroundView.frame.size.width+20*_sizeFactor, _cardContentpadding+_iconBackgroundView.frame.size.height/10, 300*_sizeFactor, 30*_sizeFactor)]; + self.hostNameLabel.numberOfLines = 1; + self.hostNameLabel.lineBreakMode = NSLineBreakByTruncatingTail; + + self.hostIconView.translatesAutoresizingMaskIntoConstraints = NO; + self.hostNameLabel.text = @"RazerBlade 16"; + self.hostNameLabel.textColor = [UIColor whiteColor]; //theme + self.hostNameLabel.font = [UIFont boldSystemFontOfSize:20*_sizeFactor]; + [self addSubview:self.hostNameLabel]; + + + + // 在线状态图标 + self.statusIcon = [[UIImageView alloc] initWithFrame:CGRectMake(180, 70, 20*_sizeFactor, 20*_sizeFactor)]; + self.statusIcon.contentMode = UIViewContentModeScaleAspectFit; + self.statusIcon.translatesAutoresizingMaskIntoConstraints = NO; + if (@available(iOS 13.0, *)) { + self.statusIcon.image = [UIImage systemImageNamed:@"wifi"]; + } else { + // Fallback on earlier versions + } + self.statusIcon.tintColor = defaultGreen; + + [self addSubview:self.statusIcon]; + [NSLayoutConstraint activateConstraints:@[ + [self.statusIcon.leadingAnchor constraintEqualToAnchor:self.hostNameLabel.leadingAnchor], + [self.statusIcon.topAnchor constraintEqualToAnchor:self.hostNameLabel.bottomAnchor constant:4*_sizeFactor], + [self.statusIcon.widthAnchor constraintEqualToConstant:19*_sizeFactor] + ]]; + + + // 在线文字 + self.statusLabel = [[UILabel alloc] initWithFrame:CGRectMake(205, 68, 100, 24)]; + self.statusLabel.translatesAutoresizingMaskIntoConstraints = NO; + self.statusLabel.text = @"Online"; + self.statusLabel.font = [UIFont systemFontOfSize:16*_sizeFactor weight:UIFontWeightMedium]; + self.statusLabel.textColor = defaultGreen; + // self.statusLabel.font = [UIFont systemFontOfSize:16*_sizeFactor]; + [self addSubview:self.statusLabel]; + [NSLayoutConstraint activateConstraints:@[ + [self.statusLabel.leadingAnchor constraintEqualToAnchor:self.statusIcon.trailingAnchor constant:3*_sizeFactor], + [self.statusLabel.centerYAnchor constraintEqualToAnchor:self.statusIcon.centerYAnchor constant:0], + ]]; + + + // 设置按钮 + /* + self.settingsButton = [UIButton buttonWithType:UIButtonTypeSystem]; + self.settingsButton.frame = CGRectMake(self.bounds.size.width - 40, 20, 24, 24); + if (@available(iOS 13.0, *)) { + [self.settingsButton setImage:[UIImage systemImageNamed:@"gearshape"] forState:UIControlStateNormal]; + } else { + // Fallback on earlier versions + } + self.settingsButton.tintColor = [UIColor lightGrayColor]; + [self addSubview:self.settingsButton]; + */ + + // 启动应用按钮 + self.leftButton = [UIButton buttonWithType:UIButtonTypeSystem]; + self.leftButton.translatesAutoresizingMaskIntoConstraints = NO; + self.leftButton.frame = CGRectMake(20, 200, 150, buttonHeight); + [self.leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Applications"] forState:UIControlStateNormal]; + [self.leftButton setTitleColor:[UIColor textColorGray] forState:UIControlStateNormal]; //theme + self.leftButton.titleLabel.font = [UIFont systemFontOfSize:16*_sizeFactor]; + [self addSubview:self.leftButton]; + [NSLayoutConstraint activateConstraints:@[ + [self.leftButton.leadingAnchor constraintEqualToAnchor:self.iconBackgroundView.leadingAnchor constant:0], + [self.leftButton.topAnchor constraintEqualToAnchor:self.iconBackgroundView.bottomAnchor constant:iconAndButtonSpacing], + [self.leftButton.widthAnchor constraintEqualToConstant:appButtonWidth], + [self.leftButton.heightAnchor constraintEqualToConstant:buttonHeight], + // [self.launchButton.titleLabel.leadingAnchor constraintEqualToAnchor:self.launchButton.imageView.trailingAnchor constant:3*_sizeFactor] + ]]; + + + // 开始串流按钮 + self.rightButton = [UIButton buttonWithType:UIButtonTypeSystem]; + self.rightButton.translatesAutoresizingMaskIntoConstraints = NO; + self.rightButton.frame = CGRectMake(0, 0, 150, 50); + self.rightButton.backgroundColor = defaultBlue; + self.rightButton.layer.cornerRadius = 10; + [self.rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Launch"] forState:UIControlStateNormal]; + [self.rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; // theme + self.rightButton.titleLabel.font = [UIFont boldSystemFontOfSize:16*_sizeFactor]; + + // self.launchButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); + self.rightButton.tintColor = [UIColor whiteColor]; + [self addSubview:self.rightButton]; + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.rightButton.frame.size.height/4*_sizeFactor]; + [self.rightButton setImage:[UIImage systemImageNamed:@"play.fill" withConfiguration:config] forState:UIControlStateNormal]; + + } else { + // Fallback on earlier versions + } + + [NSLayoutConstraint activateConstraints:@[ + [self.rightButton.leadingAnchor constraintEqualToAnchor:self.leftButton.trailingAnchor constant:15*_sizeFactor], + [self.rightButton.centerYAnchor constraintEqualToAnchor:self.leftButton.centerYAnchor constant:0], + [self.rightButton.widthAnchor constraintEqualToConstant:launchButtonWidth], + [self.rightButton.heightAnchor constraintEqualToConstant:buttonHeight], + // [self.launchButton.titleLabel.leadingAnchor constraintEqualToAnchor:self.launchButton.imageView.trailingAnchor constant:3*_sizeFactor] + ]]; + + // 配对按钮 + self.pairButton = [UIButton buttonWithType:UIButtonTypeSystem]; + self.pairButton.translatesAutoresizingMaskIntoConstraints = NO; + self.pairButton.frame = CGRectMake(0, 0, 150, 50); + self.pairButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + self.pairButton.layer.cornerRadius = 10; + [self.pairButton setTitle:[LocalizationHelper localizedStringForKey:@" Pair with PIN"] forState:UIControlStateNormal]; + [self.pairButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme + self.pairButton.titleLabel.font = [UIFont boldSystemFontOfSize:16*_sizeFactor]; + [self addSubview:self.pairButton]; + + // self.launchButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.pairButton.frame.size.height/3.5*_sizeFactor weight:UIImageSymbolWeightBold]; + UIImage *templateImage = [UIImage systemImageNamed:@"lock.open.fill" withConfiguration:config]; + UIImage *coloredImage = [templateImage imageWithTintColor:defaultBlue renderingMode:UIImageRenderingModeAlwaysOriginal]; + [self.pairButton setImage:coloredImage forState:UIControlStateNormal]; + } else { + // Fallback on earlier versions + } + _pairButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + [_pairButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme + + [NSLayoutConstraint activateConstraints:@[ + [self.pairButton.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_cardContentpadding], + [self.pairButton.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_cardContentpadding], + [self.pairButton.topAnchor constraintEqualToAnchor:self.iconBackgroundView.bottomAnchor constant:iconAndButtonSpacing], + // [self.pairButton.widthAnchor constraintEqualToConstant:launchButtonWidth], + [self.pairButton.heightAnchor constraintEqualToConstant:buttonHeight], + ]]; + + + //分隔线 + _separatorLine = [[UIView alloc] init]; + _separatorLine.backgroundColor = [UIColor colorWithWhite:0.3 alpha:5.0]; + _separatorLine.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_separatorLine]; + [NSLayoutConstraint activateConstraints:@[ + [_separatorLine.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_cardContentpadding], + [_separatorLine.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_cardContentpadding], + [_separatorLine.centerYAnchor constraintEqualToAnchor:_iconBackgroundView.bottomAnchor constant: iconAndButtonSpacing/2], + [_separatorLine.heightAnchor constraintEqualToConstant:1.0/UIScreen.mainScreen.scale] + // [self.launchButton.titleLabel.leadingAnchor constraintEqualToAnchor:self.launchButton.imageView.trailingAnchor constant:3*_sizeFactor] + ]]; + + + // [self layoutSubviews]; + // [self layoutIfNeeded]; + + _widthConstraint.constant = _cardContentpadding*2 + appButtonWidth + 15*_sizeFactor + launchButtonWidth; + _heightConstraint.constant = _cardContentpadding*2 + _iconBackgroundView.frame.size.height + iconAndButtonSpacing + buttonHeight + 1; + + + [self updateTheme:_userIterfaceStyle]; + // [self updateContentsForHost:_host]; + // [self updateTheme:UIUserInterfaceStyleLight]; +} + +- (void)createBackgroundLayer{ + backgroundLayer = [CAGradientLayer layer]; + UIColor *gradientColor = [UIColor colorWithRed:0.0 green:0.319 blue:0.64 alpha:1.0]; + CGColorRef gradientColorRef = _userIterfaceStyle == UIUserInterfaceStyleDark ? gradientColor.CGColor : [gradientColor colorWithAlphaComponent:0.52].CGColor; + backgroundLayer.colors = @[ + (__bridge id)[UIColor clearColor].CGColor, + (__bridge id)[UIColor clearColor].CGColor, + (__bridge id)[UIColor clearColor].CGColor, + (__bridge id)gradientColorRef + ]; + + backgroundLayer.locations = @[@0, @0.18, @0.5, @1]; + backgroundLayer.startPoint = CGPointMake(0.25, 0.5); + backgroundLayer.endPoint = CGPointMake(0.75, 0.5); + + CGAffineTransform transform = CGAffineTransformMake(-1.01, -1, 1, -3.67, 0.5, 2.83); + backgroundLayer.transform = CATransform3DMakeAffineTransform(transform); + [self.layer insertSublayer:backgroundLayer atIndex:0]; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + backgroundLayer.bounds = CGRectInset(self.bounds, -0.5 * self.bounds.size.width, -0.5 * self.bounds.size.height); + backgroundLayer.position = CGPointMake(CGRectGetMidX(self.bounds), CGRectGetMidY(self.bounds)); + [self updateContentsForHost:_host]; // quick update before looping +} + + +- (void)updateTheme:(UIUserInterfaceStyle)userIterfaceStyle{ + switch (userIterfaceStyle) { + case UIUserInterfaceStyleDark: + _hostNameLabel.textColor = [UIColor textColorDark]; + [_leftButton setTitleColor:[UIColor appPrimaryColor] forState:UIControlStateNormal]; + _separatorLine.backgroundColor = [UIColor separatorColorDark]; + // [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.backgroundColor = [UIColor widgetBackgroundColorDark]; + backgroundLayer.hidden = NO; + break; + case UIUserInterfaceStyleLight: + _hostNameLabel.textColor = [UIColor textColorLight]; + [_leftButton setTitleColor:[UIColor appPrimaryColor] forState:UIControlStateNormal]; + _separatorLine.backgroundColor = [UIColor separatorColorLight]; + // [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; + self.backgroundColor = [UIColor widgetBackgroundColorLight]; + backgroundLayer.hidden = NO; + break; + + default:break; + } +} + + +- (void)didMoveToSuperview { + // Start our update loop when we are added to our cell + if (self.superview != nil && _host != nil) { + [self updateLoop]; + } +} + +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; + + if (@available(iOS 13.0, *)) { + if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) { + [self updateTheme:self.traitCollection.userInterfaceStyle]; + } + } else { + [self updateTheme:UIUserInterfaceStyleDark]; + } +} + + +- (void) updateLoop { + // Stop immediately if the view has been detached + if (self.superview == nil) { + return; + } + + [self updateContentsForHost:_host]; + + // Queue the next refresh cycle + [self performSelector:@selector(updateLoop) withObject:self afterDelay:REFRESH_CYCLE]; +} + +- (void) switchButtonsForHostState:(State)hostState{ + switch (hostState) { + case StateOnline: + [self.leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Applications"] forState:UIControlStateNormal]; + [self.rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Launch"] forState:UIControlStateNormal]; + + break; + case StateOffline: + break; + case StateUnknown: + break; + } +} + +- (void) updateContentsForHost:(TemporaryHost*)host { + _hostNameLabel.text = host.name; + // self.hostNameLabel.text = @"RazerBlade 16 testttttettest"; + + + backgroundLayer.hidden = !(host.state == StateOnline && host.pairState == PairStatePaired); + + + + switch (host.state) { + case StateOnline: + [_hostSpinner stopAnimating]; + _statusLabel.textColor = defaultGreen; + _statusLabel.text = @"Online"; + _statusIcon.tintColor = defaultGreen; + + if (@available(iOS 13.0, *)) { + _statusIcon.image = [UIImage systemImageNamed:@"wifi"]; + } else { + // Fallback on earlier versions + } + _hostIconView.tintColor = [UIColor whiteColor]; + + + + if(host.pairState == PairStatePaired){ + _iconBackgroundView.backgroundColor = defaultBlue; + lockIconView.hidden = YES; + [_leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Applications"] forState:UIControlStateNormal]; + [_rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Launch"] forState:UIControlStateNormal]; + [_leftButton setEnabled:YES]; + [_rightButton setEnabled:YES]; + _leftButton.hidden = NO; + _rightButton.hidden = NO; + _pairButton.hidden = YES; + + [_leftButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.rightButton.frame.size.height/4*_sizeFactor]; + [self.rightButton setImage:[UIImage systemImageNamed:@"play.fill" withConfiguration:config] forState:UIControlStateNormal]; + } else { + // Fallback on earlier versions + } + _rightButton.backgroundColor = defaultBlue; + [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; // theme + } + else { + _iconBackgroundView.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + lockIconView.hidden = NO; + [_leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Applications"] forState:UIControlStateNormal]; + [_rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Launch"] forState:UIControlStateNormal]; + [_leftButton setEnabled:YES]; + [_rightButton setEnabled:YES]; + _leftButton.hidden = YES; + _rightButton.hidden = YES; + _pairButton.hidden = NO; + + + + [_leftButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.rightButton.frame.size.height/4*_sizeFactor]; + [self.rightButton setImage:[UIImage systemImageNamed:@"play.fill" withConfiguration:config] forState:UIControlStateNormal]; + } else { + // Fallback on earlier versions + } + _rightButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; // theme + } + + + break; + case StateOffline: + [_hostSpinner stopAnimating]; + // _iconBackgroundView.backgroundColor = _userIterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; + _iconBackgroundView.backgroundColor = _userIterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; + _statusLabel.textColor = [UIColor textColorGray]; + _statusLabel.text = @"Offline"; + _statusIcon.tintColor = [UIColor textColorGray]; + if (@available(iOS 13.0, *)) { + _statusIcon.image = [UIImage systemImageNamed:@"exclamationmark.triangle.fill"]; + } else { + // Fallback on earlier versions + } + _hostIconView.tintColor = [UIColor lowProfileGray]; + lockIconView.hidden = YES; + [_leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Test network"] forState:UIControlStateNormal]; + [_rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Wakeup"] forState:UIControlStateNormal]; + [_leftButton setEnabled:YES]; + [_rightButton setEnabled:YES]; + _leftButton.hidden = NO; + _rightButton.hidden = NO; + _pairButton.hidden = YES; + + + [_leftButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.rightButton.frame.size.height/3.5*_sizeFactor weight:UIImageSymbolWeightBold]; + UIImage *templateImage = [UIImage systemImageNamed:@"power" withConfiguration:config]; + UIImage *coloredImage = [templateImage imageWithTintColor:defaultBlue renderingMode:UIImageRenderingModeAlwaysOriginal]; + [self.rightButton setImage:coloredImage forState:UIControlStateNormal]; + } else { + // Fallback on earlier versions + } + _rightButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + [_rightButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme + + break; + case StateUnknown: + _hostSpinner.color = [UIColor whiteColor]; + [_hostSpinner startAnimating]; + // _iconBackgroundView.backgroundColor = _userIterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; + _iconBackgroundView.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + _statusLabel.textColor = [UIColor textColorGray]; + _statusLabel.text = @"Detecting..."; + _statusIcon.tintColor = [UIColor textColorGray]; + if (@available(iOS 13.0, *)) { + _statusIcon.image = [UIImage systemImageNamed:@"antenna.radiowaves.left.and.right"]; + } else { + // Fallback on earlier versions + } + // _hostIconView.tintColor = [UIColor lowProfileGray]; + _hostIconView.tintColor = defaultBlue; + lockIconView.hidden = YES; + [_leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Test network"] forState:UIControlStateNormal]; + [_rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Wakeup"] forState:UIControlStateNormal]; + [_leftButton setEnabled:NO]; + [_rightButton setEnabled:NO]; + _leftButton.hidden = NO; + _rightButton.hidden = NO; + _pairButton.hidden = YES; + + + [_leftButton setTitleColor:[UIColor textColorGray] forState:UIControlStateNormal]; // theme + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.rightButton.frame.size.height/3.5*_sizeFactor weight:UIImageSymbolWeightBold]; + UIImage *templateImage = [UIImage systemImageNamed:@"power" withConfiguration:config]; + UIImage *coloredImage = [templateImage imageWithTintColor:[UIColor textColorGray] renderingMode:UIImageRenderingModeAlwaysOriginal]; + [self.rightButton setImage:coloredImage forState:UIControlStateNormal]; + } else { + // Fallback on earlier versions + } + _rightButton.backgroundColor = [[UIColor textColorGray] colorWithAlphaComponent:0.2]; + [_rightButton setTitleColor:[UIColor textColorGray] forState:UIControlStateNormal]; // theme + + + break; + default:break; + } + + /* + if (host.state == StateOnline) { + [_hostSpinner stopAnimating]; + + lockIconView.hidden = ! (host.pairState == PairStateUnpaired); + + + if (host.pairState == PairStateUnpaired) { + + } + else { + } + + } + else if (host.state == StateOffline) { + [_hostSpinner stopAnimating]; + } + else { + [_hostSpinner startAnimating]; + } + */ +} + + + +@end diff --git a/Limelight/MenuSectionView.h b/Limelight/MenuSectionView.h new file mode 100644 index 00000000..193d5f3e --- /dev/null +++ b/Limelight/MenuSectionView.h @@ -0,0 +1,33 @@ +// +// MenuSectionView.h +// Moonlight-ZWM +// +// Created by True砖家 on 5/18/25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + +// MenuSectionView.h + +#import + +@interface MenuSectionView : UIView + +// 外部可访问属性 +@property (nonatomic, assign) CGFloat leadingTrailingPadding; +@property (nonatomic, assign) CGFloat separatorLinePadding; +@property (nonatomic, copy) NSString *sectionTitle; +@property (nonatomic, assign) BOOL expanded; +@property (nonatomic, strong) UIColor *backgroundColor; +@property (nonatomic, assign) CGFloat rootStackViewSpacing; +@property (nonatomic, assign) CGFloat headerViewHeight; +@property (nonatomic, assign) CGFloat headerViewVerticalSpacing; +@property (nonatomic, strong) NSMutableArray *subStackViews; + +// 方法 +- (void)setSectionIcon:(UIImage *)icon; +- (void)addSubStackView:(UIStackView *)stackView; +- (void)addToParentStack:(UIStackView *)parentStack; +- (void)removeSubStackView:(UIStackView *)stackView; +- (void)updateLayout; + +@end diff --git a/Limelight/MenuSectionView.m b/Limelight/MenuSectionView.m new file mode 100644 index 00000000..6df6311e --- /dev/null +++ b/Limelight/MenuSectionView.m @@ -0,0 +1,324 @@ +// +// MenuSectionView.h +// Moonlight-ZWM +// +// Created by True砖家 on 5/18/25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// +// MenuSectionView.m + +#import "MenuSectionView.h" + +@interface MenuSectionView () + +@property (nonatomic, strong) UIStackView *rootStackView; +@property (nonatomic, strong) UILabel *titleLabel; +@property (nonatomic, strong) UIImageView *iconImageView; +@property (nonatomic, strong) UIButton *toggleButton; +@property (nonatomic, strong) UIButton *toggleArea; +@property (nonatomic, strong) NSLayoutConstraint *heightConstraint; +@property (nonatomic, strong) UIView *headerView; +@property (nonatomic, strong) UIView *separatorLine; + + +@end + +@implementation MenuSectionView + +- (instancetype)initWithFrame:(CGRect)frame { + self = [super initWithFrame:frame]; + if (self) { + [self commonInit]; + } + return self; +} + +- (instancetype)initWithCoder:(NSCoder *)coder { + self = [super initWithCoder:coder]; + if (self) { + [self commonInit]; + } + return self; +} + +- (void)commonInit { + // 默认值 + _leadingTrailingPadding = 0; + _separatorLinePadding = 26; + _sectionTitle = @"Section"; + _expanded = YES; + _backgroundColor = [UIColor clearColor]; + _rootStackViewSpacing = 8.0; + _subStackViews = [NSMutableArray array]; + _headerViewHeight = 37; + _headerViewVerticalSpacing = 26; + + // 设置视图 + self.layer.cornerRadius = 10.0; + self.layer.masksToBounds = YES; + self.backgroundColor = _backgroundColor; + + // 头部视图(包含图标和标题) + _headerView = [[UIView alloc] init]; + _headerView.translatesAutoresizingMaskIntoConstraints = NO; + [self addSubview:_headerView]; + + // 图标视图 + _iconImageView = [[UIImageView alloc] init]; + _iconImageView.contentMode = UIViewContentModeScaleAspectFit; + _iconImageView.translatesAutoresizingMaskIntoConstraints = NO; + _iconImageView.tintColor = [UIColor whiteColor]; + [_headerView addSubview:_iconImageView]; + + // 标题标签 + _titleLabel = [[UILabel alloc] init]; + _titleLabel.text = _sectionTitle; + _titleLabel.font = [UIFont systemFontOfSize:27 weight:UIFontWeightMedium]; + _titleLabel.textAlignment = NSTextAlignmentLeft; + _titleLabel.translatesAutoresizingMaskIntoConstraints = NO; + [_headerView addSubview:_titleLabel]; + + // 切换按钮 + _toggleButton = [UIButton buttonWithType:UIButtonTypeSystem]; + _toggleArea = [UIButton buttonWithType:UIButtonTypeSystem]; + if (@available(iOS 13.0, *)) { + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:_headerViewHeight*0.31 weight:UIImageSymbolWeightMedium]; + [_toggleButton setImage:[UIImage systemImageNamed:@"chevron.left" withConfiguration:config] forState:UIControlStateNormal]; + } else { + [_toggleButton setTitle:@"<" forState:UIControlStateNormal]; + } + [_toggleButton addTarget:self action:@selector(toggleFold) forControlEvents:UIControlEventTouchUpInside]; + [_toggleArea addTarget:self action:@selector(toggleFold) forControlEvents:UIControlEventTouchUpInside]; + _toggleButton.translatesAutoresizingMaskIntoConstraints = NO; + _toggleArea.translatesAutoresizingMaskIntoConstraints = NO; + _toggleButton.contentEdgeInsets = UIEdgeInsetsMake(-10,-10,-10,-10); // 上下左右各扩展 20pt + [_headerView addSubview:_toggleButton]; + [_headerView addSubview:_toggleArea]; + + // 根stackView + _rootStackView = [[UIStackView alloc] init]; + _rootStackView.axis = UILayoutConstraintAxisVertical; + _rootStackView.spacing = _rootStackViewSpacing; + _rootStackView.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:_rootStackView]; + + // 分隔线 + _separatorLine = [[UIView alloc] init]; + _separatorLine.backgroundColor = [UIColor colorWithWhite:0.2 alpha:5.0]; + _separatorLine.translatesAutoresizingMaskIntoConstraints = NO; + + [self addSubview:_separatorLine]; + + // 高度约束 + _heightConstraint = [self.heightAnchor constraintEqualToConstant:44]; + _heightConstraint.active = YES; + + // 布局 + [self setupConstraints]; + [self updateViewForFoldState]; +} + +- (void)setupConstraints { + // 头部视图约束 + [NSLayoutConstraint activateConstraints:@[ + [_headerView.topAnchor constraintEqualToAnchor:self.topAnchor], + [_headerView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], + [_headerView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + [_headerView.heightAnchor constraintEqualToConstant:_headerViewHeight] + ]]; + + // 图标约束 + [NSLayoutConstraint activateConstraints:@[ + [_iconImageView.leadingAnchor constraintEqualToAnchor:_headerView.leadingAnchor constant:_leadingTrailingPadding], + [_iconImageView.centerYAnchor constraintEqualToAnchor:_headerView.centerYAnchor], + // [_iconImageView.topAnchor constraintEqualToAnchor:_headerView.topAnchor], + [_iconImageView.widthAnchor constraintEqualToConstant:_headerViewHeight], + [_iconImageView.heightAnchor constraintEqualToConstant:_headerViewHeight] + ]]; + + // 标题约束 + [NSLayoutConstraint activateConstraints:@[ + [_titleLabel.leadingAnchor constraintEqualToAnchor:_iconImageView.trailingAnchor constant:8], + [_titleLabel.centerYAnchor constraintEqualToAnchor:_headerView.centerYAnchor], + [_titleLabel.trailingAnchor constraintEqualToAnchor:_toggleButton.leadingAnchor constant:-8] + ]]; + + // 切换按钮约束 + [NSLayoutConstraint activateConstraints:@[ + [_toggleButton.trailingAnchor constraintEqualToAnchor:_headerView.trailingAnchor constant:-_leadingTrailingPadding], + [_toggleButton.centerYAnchor constraintEqualToAnchor:_headerView.centerYAnchor], + [_toggleButton.widthAnchor constraintEqualToConstant:_headerViewHeight*0.8], + [_toggleButton.heightAnchor constraintEqualToConstant:_headerViewHeight*0.8] + ]]; + + [NSLayoutConstraint activateConstraints:@[ + [_toggleArea.leadingAnchor constraintEqualToAnchor:_headerView.leadingAnchor], + [_toggleArea.centerYAnchor constraintEqualToAnchor:_headerView.centerYAnchor], + [_toggleArea.trailingAnchor constraintEqualToAnchor:_toggleButton.leadingAnchor], + //[_toggleArea.widthAnchor constraintEqualToConstant:_headerViewHeight], + [_toggleArea.heightAnchor constraintEqualToConstant:_headerViewHeight] + ]]; + + [self layoutIfNeeded]; + + // 根stackView约束 + [NSLayoutConstraint activateConstraints:@[ + [_rootStackView.topAnchor constraintEqualToAnchor:self.topAnchor constant:_headerViewHeight+_headerViewVerticalSpacing], + [_rootStackView.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:_leadingTrailingPadding], + [_rootStackView.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-_leadingTrailingPadding], + [_rootStackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-1] // 为分隔线留出空间 + ]]; + + // 分隔线约束 + [NSLayoutConstraint activateConstraints:@[ + [_separatorLine.leadingAnchor constraintEqualToAnchor:self.leadingAnchor], + [_separatorLine.trailingAnchor constraintEqualToAnchor:self.trailingAnchor], + [_separatorLine.bottomAnchor constraintEqualToAnchor:self.bottomAnchor], + [_separatorLine.heightAnchor constraintEqualToConstant:1.0] + ]]; + + [NSLayoutConstraint activateConstraints:@[ + [self.headerView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0], + [self.rootStackView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:0], + ]]; +} + +#pragma mark - Public Methods + +- (void)setSectionIcon:(UIImage *)icon { + _iconImageView.image = icon; + _iconImageView.hidden = (icon == nil); + [self updateLayout]; +} + +- (void)setLeadingTrailingPadding:(CGFloat)leadingTrailingPadding { + _leadingTrailingPadding = leadingTrailingPadding; + [self updateLayout]; +} + +- (void)setSectionTitle:(NSString *)sectionTitle { + _sectionTitle = sectionTitle; + _titleLabel.text = sectionTitle; +} + +- (void)setExpanded:(BOOL)isExpanded { + if (_expanded != isExpanded) { + _expanded = isExpanded;} + [self updateViewForFoldState]; +} + +- (void)setBackgroundColor:(UIColor *)backgroundColor { + [super setBackgroundColor:backgroundColor]; + _backgroundColor = backgroundColor; +} + +- (void)setRootStackViewSpacing:(CGFloat)rootStackViewSpacing { + _rootStackViewSpacing = rootStackViewSpacing; + _rootStackView.spacing = rootStackViewSpacing; + [self updateLayout]; +} + +- (void)addSubStackView:(UIStackView *)stackView { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + if (![_subStackViews containsObject:stackView]) { + [_subStackViews addObject:stackView]; + [_rootStackView addArrangedSubview:stackView]; + [_rootStackView layoutIfNeeded]; + [self updateLayout]; + } + [CATransaction commit]; + // NSLog(@"rootStack height2: %f", _rootStackView.frame.size.height); +} + +- (void)addToParentStack:(UIStackView *)parentStack { + [parentStack addArrangedSubview:self]; + self.translatesAutoresizingMaskIntoConstraints = NO; + [NSLayoutConstraint activateConstraints:@[ + [self.leadingAnchor constraintEqualToAnchor:parentStack.leadingAnchor constant:0], + [self.trailingAnchor constraintEqualToAnchor:parentStack.trailingAnchor constant:0], + ]]; +} + +- (void)removeSubStackView:(UIStackView *)stackView { + [CATransaction begin]; + [CATransaction setDisableActions:YES]; + if ([_subStackViews containsObject:stackView]) { + [_subStackViews removeObject:stackView]; + [_rootStackView removeArrangedSubview:stackView]; + [stackView removeFromSuperview]; + [self updateLayout]; + } + [CATransaction commit]; +} + + +- (void)updateLayout { + // 更新边距约束 + for (NSLayoutConstraint *constraint in self.constraints) { + if (constraint.firstItem == _rootStackView && constraint.firstAttribute == NSLayoutAttributeLeading) { + constraint.constant = _leadingTrailingPadding; + } else if (constraint.firstItem == _rootStackView && constraint.firstAttribute == NSLayoutAttributeTrailing) { + constraint.constant = -_leadingTrailingPadding; + } + } + + for (NSLayoutConstraint *constraint in _headerView.constraints) { + if (constraint.firstItem == _iconImageView && constraint.firstAttribute == NSLayoutAttributeLeading) { + constraint.constant = _leadingTrailingPadding; + } else if (constraint.firstItem == _toggleButton && constraint.firstAttribute == NSLayoutAttributeTrailing) { + constraint.constant = -_leadingTrailingPadding; + } + } + + [self setNeedsLayout]; + [self layoutIfNeeded]; +} + +#pragma mark - Private Methods + +- (void)toggleFold { + self.expanded = !self.expanded; + [self updateViewForFoldState]; +} + +- (void)updateViewForFoldState { + [self setupConstraints]; + if (_expanded) { + _rootStackView.hidden = NO; + _separatorLine.hidden = NO; + CGSize fittingSize = [self.rootStackView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + CGFloat rootStackViewHeight = fittingSize.height; + fittingSize = [self.headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + CGFloat headerHeight = fittingSize.height; + + self.heightConstraint.constant = headerHeight + _headerViewVerticalSpacing + rootStackViewHeight + _separatorLinePadding + 1; + + [UIView animateWithDuration:0 animations:^{ + self.toggleButton.transform = CGAffineTransformMakeRotation(M_PI+M_PI_2); + [NSLayoutConstraint activateConstraints:@[ + [self.rootStackView.bottomAnchor constraintEqualToAnchor:self.bottomAnchor constant:-self.separatorLinePadding], + // [self.rootStackView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:0], + ]]; + [self layoutIfNeeded]; + }]; + } else { + // 折叠状态 + CGSize fittingSize = [self.headerView systemLayoutSizeFittingSize:UILayoutFittingCompressedSize]; + _rootStackView.hidden = YES; + _separatorLine.hidden = NO; + _heightConstraint.constant = fittingSize.height + _headerViewVerticalSpacing; + // [self updateLayout]; + [UIView animateWithDuration:0 animations:^{ + self.toggleButton.transform = CGAffineTransformIdentity; + [NSLayoutConstraint activateConstraints:@[ + [self.headerView.topAnchor constraintEqualToAnchor:self.topAnchor constant:0], + // [self.rootStackView.topAnchor constraintEqualToAnchor:self.headerView.bottomAnchor constant:0], + ]]; + [self layoutIfNeeded]; + }]; + } +} + +@end diff --git a/Limelight/UIColor+Theme.h b/Limelight/UIColor+Theme.h new file mode 100644 index 00000000..ea2120ef --- /dev/null +++ b/Limelight/UIColor+Theme.h @@ -0,0 +1,28 @@ +// +// UIColor+Theme.h +// Moonlight-ZWM +// +// Created by True砖家 on 2025.5.25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + +#import + +@interface UIColor (Theme) + ++ (UIColor *)appPrimaryColor; ++ (UIColor *)appSecondaryColor; ++ (UIColor *)appPrimaryColorWithAlpha; ++ (UIColor *)widgetBackgroundColorDark; ++ (UIColor *)widgetBackgroundColorLight; ++ (UIColor *)separatorColorDark; ++ (UIColor *)separatorColorLight; ++ (UIColor *)textColorDark; ++ (UIColor *)textColorLight; ++ (UIColor *)appBackgroundColorDark; ++ (UIColor *)appBackgroundColorLight; ++ (UIColor *)textColorGray; ++ (UIColor *)lowProfileGray; + +@end + diff --git a/Limelight/UIColor+Theme.m b/Limelight/UIColor+Theme.m new file mode 100644 index 00000000..c063de77 --- /dev/null +++ b/Limelight/UIColor+Theme.m @@ -0,0 +1,67 @@ +// +// UIColor+Theme.h +// Moonlight-ZWM +// +// Created by True砖家 on 2025.5.25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + +#import "UIColor+Theme.h" + +@implementation UIColor (Theme) + ++ (UIColor *)appPrimaryColor { + return [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0]; // #0A84FF +} + ++ (UIColor *)appSecondaryColor { + return [UIColor colorWithRed:0.0 green:0.48 blue:1.0 alpha:1.0]; // 可换其他常用色 +} + ++ (UIColor *)appPrimaryColorWithAlpha { + return [[UIColor appPrimaryColor] colorWithAlphaComponent:0.24]; // #0A84FF +} + + ++ (UIColor *)widgetBackgroundColorDark{ + return [UIColor colorWithRed:44.0/255.0 green:44.0/255.0 blue:46.0/255.0 alpha:1.0]; +} + ++ (UIColor *)widgetBackgroundColorLight{ + return [UIColor colorWithRed:242.0/255.0 green:242.0/255.0 blue:247.0/255.0 alpha:1.0]; +} + ++ (UIColor *)separatorColorDark{ + return [UIColor colorWithWhite:0.28 alpha:1.0]; +} + ++ (UIColor *)separatorColorLight{ + return [UIColor colorWithWhite:0.1 alpha:0.28]; +} + ++ (UIColor *)textColorDark{ + return [UIColor whiteColor]; +} + ++ (UIColor *)textColorLight{ + return [UIColor blackColor]; +} + ++ (UIColor *)textColorGray{ + return [UIColor colorWithRed:0.55 green:0.55 blue:0.6 alpha:0.95]; +} + ++ (UIColor *)lowProfileGray{ + return [UIColor colorWithRed:0.65 green:0.65 blue:0.65 alpha:0.4]; +} + ++ (UIColor *)appBackgroundColorDark { + return [UIColor colorWithRed:28.0/255.0 green:28.0/255.0 blue:30.0/255.0 alpha:1.0]; +} + ++ (UIColor *)appBackgroundColorLight { + return [UIColor whiteColor]; +} + + +@end diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index b56987f1..95fe7287 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -32,6 +32,8 @@ #import "LocalizationHelper.h" #import "CustomEdgeSlideGestureRecognizer.h" #import "DataManager.h" +#import "HostCardView.h" +#import "UIColor+Theme.h" #import "Moonlight-Swift.h" // not used yet. #if !TARGET_OS_TV @@ -314,7 +316,7 @@ static NSMutableSet* hostList; [self updateTitle]; [self disableUpButton]; [self.collectionView removeFromSuperview]; // necessary for new scroll host view reloading mechanism - [self.view setBackgroundColor:[UIColor darkGrayColor]]; + [self reloadScrollHostView]; // host view must be reloaded here } @@ -972,16 +974,27 @@ static NSMutableSet* hostList; // Fallback on earlier versions } [settingsViewController.resolutionSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.resolutionStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.framerateSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.fpsStack.hidden = self.settingsExpandedInStreamView; [settingsViewController widget:settingsViewController.bitrateSlider setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.bitrateStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.optimizeSettingsSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.optimizeSettingsStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.audioOnPCSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.audioOnPcStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.codecSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.codecStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.yuv444Selector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.yuv444Stack.hidden = self.settingsExpandedInStreamView; [settingsViewController.hdrSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.HdrStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.framePacingSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.framepacingStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.btMouseSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.citrixX1MouseStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.externalDisplayModeSelector setEnabled:!self.settingsExpandedInStreamView]; + settingsViewController.externalDisplayModeStack.hidden = self.settingsExpandedInStreamView; [settingsViewController.backToStreamingButton setEnabled:self.settingsExpandedInStreamView]; // will be deprecated soon // [settingsViewController.unlockDisplayOrientationSelector setEnabled:!self.settingsExpandedInStreamView && [self isFullScreenRequired]];//need "requires fullscreen" enabled in the app bunddle to make runtime orientation limitation woring } @@ -1116,10 +1129,10 @@ static NSMutableSet* hostList; // return isPortrait; } -- (void)viewDidLoad -{ +- (void)viewDidLoad{ [super viewDidLoad]; //[OrientationHelper updateOrientationToLandscape]; + #if !TARGET_OS_TV self.settingsExpandedInStreamView = false; // init this flag self.revealViewController.isStreaming = false; //init this flag for rvlVC @@ -1216,6 +1229,10 @@ static NSMutableSet* hostList; [self.view addSubview:hostScrollView]; if ([hostList count] == 1) [self hostClicked:[hostList anyObject] view:nil]; // auto click for single host + + + + //if([SettingsViewController isLandscapeNow] != _streamConfig.width > _streamConfig.height) //[self simulateSettingsButtonPress]; //force expand setting view if orientation changed since last quit from app. //[self simulateSettingsButtonPress]; //force expand setting view if orientation changed since last quit from app. @@ -1225,8 +1242,7 @@ static NSMutableSet* hostList; // [settingsViewController updateResolutionTable]; } --(void)handleRealOrientationChange{ - +-(void)viewDidLayoutSubviews{ } -(void)reloadScrollHostView{ @@ -1418,6 +1434,7 @@ static NSMutableSet* hostList; - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:NO]; + [self reloadScrollHostView]; [self attachWaterMark]; #if !TARGET_OS_TV @@ -1462,6 +1479,13 @@ static NSMutableSet* hostList; - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; + + /* this makes background color works*/ + for (UIView *subview in self.view.subviews) { + [subview removeFromSuperview]; // 暂时移除所有子视图 + } + + self.view.backgroundColor = [UIColor appBackgroundColorDark]; //theme test // We can get here on home press while streaming // since the stream view segues to us just before @@ -1568,7 +1592,25 @@ static NSMutableSet* hostList; // Sort the host list in alphabetical order NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)]; for (TemporaryHost* comp in sortedHostList) { - compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self]; + compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self]; // host view created here + + // new host card test + // if([comp.name isEqualToString: @"ASRockPC"]) { + if([comp.name isEqualToString: @"PianoServer"]) { + //if([comp.name isEqualToString: @"TrueZj"]) { + HostCardView *testCard = [[HostCardView alloc] initWithHost:comp]; + + [self.view addSubview:testCard]; + // [testCard resizeBySizeFactor:3]; + [NSLayoutConstraint activateConstraints:@[ + [testCard.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor constant:0], + [testCard.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor constant:150], + ]]; + + } + // + + compView.center = CGPointMake([self getCompViewX:compView addComp:addComp prevEdge:prevEdge], hostScrollView.frame.size.height / 2); prevEdge = compView.frame.origin.x + compView.frame.size.width; [hostScrollView addSubview:compView]; diff --git a/Limelight/ViewControllers/SettingsViewController.m b/Limelight/ViewControllers/SettingsViewController.m index 210367e9..5a2d959b 100644 --- a/Limelight/ViewControllers/SettingsViewController.m +++ b/Limelight/ViewControllers/SettingsViewController.m @@ -12,6 +12,7 @@ #import "SettingsViewController.h" #import "TemporarySettings.h" #import "DataManager.h" +#import "MenuSectionView.h" #import #import @@ -340,6 +341,51 @@ BOOL isCustomResolution(CGSize res) { return [self isIPhone] ? UINavigationBarHeightIPhone : UINavigationBarHeightIPad; } + +- (void)initParentStack{ + self.scrollView.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentAutomatic; + // 可选:确保 scrollView 开启垂直滚动 + self.scrollView.alwaysBounceVertical = YES; + parentStack = [[UIStackView alloc] init]; + parentStack.axis = UILayoutConstraintAxisVertical; + parentStack.spacing = 0; + parentStack.translatesAutoresizingMaskIntoConstraints = NO; + [self.scrollView addSubview:parentStack]; + [NSLayoutConstraint activateConstraints:@[ + [parentStack.topAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.topAnchor constant: [self getStandardNavBarHeight] + 13], + [parentStack.bottomAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.bottomAnchor constant:-20], + [parentStack.leadingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.leadingAnchor constant: 14], + [parentStack.trailingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.trailingAnchor constant: -15], + [parentStack.widthAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.widthAnchor] + ]]; +} + +- (void)layoutSections{ + MenuSectionView *videoSection = [[MenuSectionView alloc] init]; + videoSection.sectionTitle = [LocalizationHelper localizedStringForKey:@"Video"]; + if (@available(iOS 13.0, *)) { + [videoSection setSectionIcon:[UIImage systemImageNamed:@"airplayvideo"]]; + } else [videoSection setSectionIcon:nil]; + [videoSection addSubStackView:_resolutionStack]; + [videoSection addSubStackView:_fpsStack]; + [videoSection addSubStackView:_codecStack]; + [videoSection addToParentStack:parentStack]; + [videoSection setExpanded:YES]; + + 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]; + [gesturesSection addSubStackView:_keyboardToggleFingerNumStack]; + [gesturesSection addSubStackView:_slideToSettingsScreenEdgeStack]; + [gesturesSection addSubStackView:_slideToCmdToolScreenEdgeStack]; + [gesturesSection addSubStackView:_slideToSettingsDistanceStack]; + [gesturesSection addToParentStack:parentStack]; + [gesturesSection setExpanded:YES]; +} + + - (void)layoutWidgetes { // [self.view addSubview:self.navigationBar]; @@ -349,60 +395,65 @@ BOOL isCustomResolution(CGSize res) { // 可选:确保 scrollView 开启垂直滚动 self.scrollView.alwaysBounceVertical = YES; - parentStack = [[UIStackView alloc] init]; - parentStack.axis = UILayoutConstraintAxisVertical; - parentStack.spacing = 13; - parentStack.translatesAutoresizingMaskIntoConstraints = NO; - [self.scrollView addSubview:parentStack]; + UIStackView* parentStackTmp = [[UIStackView alloc] init]; + parentStackTmp.axis = UILayoutConstraintAxisVertical; + parentStackTmp.spacing = 13; + parentStackTmp.translatesAutoresizingMaskIntoConstraints = NO; + [self.scrollView addSubview:parentStackTmp]; [NSLayoutConstraint activateConstraints:@[ - [parentStack.topAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.topAnchor constant: [self getStandardNavBarHeight] + 20], - [parentStack.bottomAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.bottomAnchor constant:-20], - [parentStack.leadingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.leadingAnchor constant: 14], - [parentStack.trailingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.trailingAnchor constant: -15], - [parentStack.widthAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.widthAnchor] + [parentStackTmp.topAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.topAnchor constant: [self getStandardNavBarHeight] + 300], + [parentStackTmp.bottomAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.bottomAnchor constant:-20], + [parentStackTmp.leadingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.leadingAnchor constant: 14], + [parentStackTmp.trailingAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.trailingAnchor constant: -15], + [parentStackTmp.widthAnchor constraintEqualToAnchor:self.scrollView.contentLayoutGuide.widthAnchor] ]]; - [parentStack addArrangedSubview:self.resolutionStack]; + + [parentStackTmp addArrangedSubview:self.resolutionStack]; // self.resolutionStack.hidden = YES; - [parentStack addArrangedSubview:self.fpsStack]; + [parentStackTmp addArrangedSubview:self.fpsStack]; // self.fpsStack.hidden = YES; - [parentStack addArrangedSubview:self.bitrateStack]; + [parentStackTmp addArrangedSubview:self.bitrateStack]; // self.bitrateStack.hidden = YES; - [parentStack addArrangedSubview:self.touchModeStack]; - [parentStack addArrangedSubview:self.asyncTouchStack]; - [parentStack addArrangedSubview:self.pointerVelocityDividerStack]; - [parentStack addArrangedSubview:self.pointerVelocityFactorStack]; - [parentStack addArrangedSubview:self.touchMoveEventIntervalStack]; - [parentStack addArrangedSubview:self.mousePointerVelocityStack]; - [parentStack addArrangedSubview:self.onScreenWidgetStack]; - [parentStack addArrangedSubview:self.keyboardToggleFingerNumStack]; - [parentStack addArrangedSubview:self.liftStreamViewForKeyboardStack]; - [parentStack addArrangedSubview:self.showKeyboardToolbarStack]; - [parentStack addArrangedSubview:self.slideToSettingsScreenEdgeStack]; - [parentStack addArrangedSubview:self.slideToCmdToolScreenEdgeStack]; - [parentStack addArrangedSubview:self.slideToSettingsDistanceStack]; - [parentStack addArrangedSubview:self.optimizeSettingsStack]; - [parentStack addArrangedSubview:self.multiControllerStack]; - [parentStack addArrangedSubview:self.swapAbaxyStack]; - [parentStack addArrangedSubview:self.audioOnPcStack]; - [parentStack addArrangedSubview:self.codecStack]; - [parentStack addArrangedSubview:self.yuv444Stack]; - [parentStack addArrangedSubview:self.HdrStack]; - [parentStack addArrangedSubview:self.framepacingStack]; - [parentStack addArrangedSubview:self.reverseMouseWheelDirectionStack]; - [parentStack addArrangedSubview:self.citrixX1MouseStack]; - [parentStack addArrangedSubview:self.statsOverlayStack]; - [parentStack addArrangedSubview:self.unlockDisplayOrientationStack]; - [parentStack addArrangedSubview:self.externalDisplayModeStack]; - [parentStack addArrangedSubview:self.localMousePointerModeStack]; + [parentStackTmp addArrangedSubview:self.touchModeStack]; + [parentStackTmp addArrangedSubview:self.asyncTouchStack]; + [parentStackTmp addArrangedSubview:self.pointerVelocityDividerStack]; + [parentStackTmp addArrangedSubview:self.pointerVelocityFactorStack]; + [parentStackTmp addArrangedSubview:self.touchMoveEventIntervalStack]; + [parentStackTmp addArrangedSubview:self.mousePointerVelocityStack]; + [parentStackTmp addArrangedSubview:self.onScreenWidgetStack]; + [parentStackTmp addArrangedSubview:self.keyboardToggleFingerNumStack]; + [parentStackTmp addArrangedSubview:self.liftStreamViewForKeyboardStack]; + [parentStackTmp addArrangedSubview:self.showKeyboardToolbarStack]; + [parentStackTmp addArrangedSubview:self.slideToSettingsScreenEdgeStack]; + [parentStackTmp addArrangedSubview:self.slideToCmdToolScreenEdgeStack]; + [parentStackTmp addArrangedSubview:self.slideToSettingsDistanceStack]; + [parentStackTmp addArrangedSubview:self.optimizeSettingsStack]; + [parentStackTmp addArrangedSubview:self.multiControllerStack]; + [parentStackTmp addArrangedSubview:self.swapAbaxyStack]; + [parentStackTmp addArrangedSubview:self.audioOnPcStack]; + [parentStackTmp addArrangedSubview:self.codecStack]; + [parentStackTmp addArrangedSubview:self.yuv444Stack]; + [parentStackTmp addArrangedSubview:self.HdrStack]; + [parentStackTmp addArrangedSubview:self.framepacingStack]; + [parentStackTmp addArrangedSubview:self.reverseMouseWheelDirectionStack]; + [parentStackTmp addArrangedSubview:self.citrixX1MouseStack]; + [parentStackTmp addArrangedSubview:self.statsOverlayStack]; + [parentStackTmp addArrangedSubview:self.unlockDisplayOrientationStack]; + [parentStackTmp addArrangedSubview:self.externalDisplayModeStack]; + [parentStackTmp addArrangedSubview:self.localMousePointerModeStack]; + [parentStackTmp removeFromSuperview]; } - - (void)viewDidLoad { - //[self pushDownExistingWidgets]; - //[self addExitButtonOnTop]; + BOOL isIPad = ([UIDevice currentDevice].userInterfaceIdiom == UIUserInterfaceIdiomPad); - if(isIPad) [self layoutWidgetes]; // layout for ipad tmply + if(isIPad) [self layoutWidgetes]; // layout for ipad tmply + + [self initParentStack]; + [self layoutSections]; + + self->slideToCloseSettingsViewRecognizer = [[CustomEdgeSlideGestureRecognizer alloc] initWithTarget:self action:@selector(edgeSwiped)]; slideToCloseSettingsViewRecognizer.edges = UIRectEdgeLeft; diff --git a/Limelight/main.m b/Limelight/main.m index 0dbc0e3e..fe1617e0 100644 --- a/Limelight/main.m +++ b/Limelight/main.m @@ -20,3 +20,4 @@ int main(int argc, char * argv[]) return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); } } + diff --git a/Moonlight.xcodeproj/project.pbxproj b/Moonlight.xcodeproj/project.pbxproj index 38526aa1..62ff1b55 100644 --- a/Moonlight.xcodeproj/project.pbxproj +++ b/Moonlight.xcodeproj/project.pbxproj @@ -8,7 +8,8 @@ /* Begin PBXBuildFile section */ 840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */; }; - 84203F232C5F24C00032EEED /* OnScreenButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84203F222C5F24C00032EEED /* OnScreenButtonView.swift */; }; + 841BAC922DE35D6B00DA639E /* UIColor+Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = 841BAC912DE35D6B00DA639E /* UIColor+Theme.m */; }; + 84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */; }; 84351B0E2C29ACCB00A77989 /* LayoutOnScreenControls.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B072C29ACCA00A77989 /* LayoutOnScreenControls.m */; }; 84351B0F2C29ACCB00A77989 /* OnScreenButtonState.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B092C29ACCA00A77989 /* OnScreenButtonState.m */; }; 84351B102C29ACCB00A77989 /* OSCProfile.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B0A2C29ACCA00A77989 /* OSCProfile.m */; }; @@ -18,6 +19,7 @@ 84351B2D2C29AD6100A77989 /* ToolBarContainerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B292C29AD6000A77989 /* ToolBarContainerView.m */; }; 84351B5C2C29ADBE00A77989 /* ProfileTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 84351B592C29ADBE00A77989 /* ProfileTableViewCell.m */; }; 84351B5D2C29ADBE00A77989 /* ProfileTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 84351B5B2C29ADBE00A77989 /* ProfileTableViewCell.xib */; }; + 843667F02D9D7173004A7D7F /* widgetTemplates.bin in Resources */ = {isa = PBXBuildFile; fileRef = 843667EF2D9D7173004A7D7F /* widgetTemplates.bin */; }; 843CC7F02C1E757D00BBC475 /* NativeTouchPointer.m in Sources */ = {isa = PBXBuildFile; fileRef = 843CC7EF2C1E757D00BBC475 /* NativeTouchPointer.m */; }; 843CC7F62C1E7A1700BBC475 /* NativeTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 843CC7F52C1E7A1700BBC475 /* NativeTouchHandler.m */; }; 843E93BE2C41528700B1651F /* OrientationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 843E93BD2C41528700B1651F /* OrientationHelper.swift */; }; @@ -25,6 +27,8 @@ 8454AC662C31907F00F0A302 /* iPad.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8454AC682C31907F00F0A302 /* iPad.storyboard */; }; 8454AC6A2C319BDA00F0A302 /* iPhone.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8454AC6C2C319BDA00F0A302 /* iPhone.storyboard */; }; 84591A512BE1625E006AAB10 /* CustomEdgeSlideGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 84591A502BE1625E006AAB10 /* CustomEdgeSlideGestureRecognizer.m */; }; + 847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */ = {isa = PBXBuildFile; fileRef = 847D2FDA2DDA015F00937A62 /* MenuSectionView.m */; }; + 848F456A2DDCD12500581E36 /* HostCardView.m in Sources */ = {isa = PBXBuildFile; fileRef = 848F45692DDCD12500581E36 /* HostCardView.m */; }; 84E1CDEC2C4F67D300547904 /* CommandManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CDEB2C4F67D300547904 /* CommandManager.swift */; }; 84E1CDEF2C4F688E00547904 /* CommandManagerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CDEE2C4F688E00547904 /* CommandManagerViewController.swift */; }; 84E1CDFA2C4FE83400547904 /* SwiftLocalizationHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84E1CDF92C4FE83400547904 /* SwiftLocalizationHelper.swift */; }; @@ -127,7 +131,9 @@ 693B3A9A218638CD00982F7B /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; 840751B12BF49B5A0096B657 /* CustomTapGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomTapGestureRecognizer.h; sourceTree = ""; }; 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CustomTapGestureRecognizer.m; sourceTree = ""; }; - 84203F222C5F24C00032EEED /* OnScreenButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnScreenButtonView.swift; sourceTree = ""; }; + 841BAC8F2DE35BEC00DA639E /* UIColor+Theme.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIColor+Theme.h"; sourceTree = ""; }; + 841BAC912DE35D6B00DA639E /* UIColor+Theme.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UIColor+Theme.m"; sourceTree = ""; }; + 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnScreenWidgetView.swift; sourceTree = ""; }; 84351B062C29ACCA00A77989 /* OnScreenButtonState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OnScreenButtonState.h; sourceTree = ""; }; 84351B072C29ACCA00A77989 /* LayoutOnScreenControls.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LayoutOnScreenControls.m; sourceTree = ""; }; 84351B082C29ACCA00A77989 /* OSCProfilesManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OSCProfilesManager.h; sourceTree = ""; }; @@ -145,6 +151,7 @@ 84351B592C29ADBE00A77989 /* ProfileTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProfileTableViewCell.m; sourceTree = ""; }; 84351B5A2C29ADBE00A77989 /* ProfileTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ProfileTableViewCell.h; sourceTree = ""; }; 84351B5B2C29ADBE00A77989 /* ProfileTableViewCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ProfileTableViewCell.xib; sourceTree = ""; }; + 843667EF2D9D7173004A7D7F /* widgetTemplates.bin */ = {isa = PBXFileReference; lastKnownFileType = archive.macbinary; name = widgetTemplates.bin; path = Limelight/PresetConfigs/widgetTemplates.bin; sourceTree = SOURCE_ROOT; }; 843CC7EE2C1E757D00BBC475 /* NativeTouchPointer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NativeTouchPointer.h; sourceTree = ""; }; 843CC7EF2C1E757D00BBC475 /* NativeTouchPointer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NativeTouchPointer.m; sourceTree = ""; }; 843CC7F42C1E778000BBC475 /* NativeTouchHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeTouchHandler.h; sourceTree = ""; }; @@ -158,6 +165,10 @@ 8454AC6D2C319BDA00F0A302 /* mul */ = {isa = PBXFileReference; lastKnownFileType = text.json.xcstrings; name = mul; path = mul.lproj/iPhone.xcstrings; sourceTree = ""; }; 84591A4F2BE16240006AAB10 /* CustomEdgeSlideGestureRecognizer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomEdgeSlideGestureRecognizer.h; sourceTree = ""; }; 84591A502BE1625E006AAB10 /* CustomEdgeSlideGestureRecognizer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomEdgeSlideGestureRecognizer.m; sourceTree = ""; }; + 847D2FD82DDA00C800937A62 /* MenuSectionView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MenuSectionView.h; sourceTree = ""; }; + 847D2FDA2DDA015F00937A62 /* MenuSectionView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MenuSectionView.m; sourceTree = ""; }; + 848F45682DDCD0D600581E36 /* HostCardView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HostCardView.h; sourceTree = ""; }; + 848F45692DDCD12500581E36 /* HostCardView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HostCardView.m; sourceTree = ""; }; 84D8EB932C5146AD00FC10A9 /* Moonlight-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Moonlight-Bridging-Header.h"; sourceTree = ""; }; 84E1CDEB2C4F67D300547904 /* CommandManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandManager.swift; sourceTree = ""; }; 84E1CDEE2C4F688E00547904 /* CommandManagerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommandManagerViewController.swift; sourceTree = ""; }; @@ -375,6 +386,14 @@ path = Cells; sourceTree = ""; }; + 843667ED2D9D70A3004A7D7F /* PresetConfigs */ = { + isa = PBXGroup; + children = ( + 843667EF2D9D7173004A7D7F /* widgetTemplates.bin */, + ); + name = PresetConfigs; + sourceTree = ""; + }; 84FD0B492C312C0B006B5BE5 /* Localization */ = { isa = PBXGroup; children = ( @@ -479,6 +498,12 @@ FB290CFA19B2C406004C83CF /* Supporting Files */, FB290D0219B2C406004C83CF /* AppDelegate.h */, FB290D0319B2C406004C83CF /* AppDelegate.m */, + 848F45682DDCD0D600581E36 /* HostCardView.h */, + 848F45692DDCD12500581E36 /* HostCardView.m */, + 841BAC8F2DE35BEC00DA639E /* UIColor+Theme.h */, + 841BAC912DE35D6B00DA639E /* UIColor+Theme.m */, + 847D2FD82DDA00C800937A62 /* MenuSectionView.h */, + 847D2FDA2DDA015F00937A62 /* MenuSectionView.m */, FBDE86DE19F7A837001C18A8 /* UIComputerView.h */, FBDE86DF19F7A837001C18A8 /* UIComputerView.m */, FBDE86E419F82297001C18A8 /* UIAppView.h */, @@ -499,6 +524,7 @@ FB290CFA19B2C406004C83CF /* Supporting Files */ = { isa = PBXGroup; children = ( + 843667ED2D9D70A3004A7D7F /* PresetConfigs */, FB290CFB19B2C406004C83CF /* Limelight-Info.plist */, FB290CFC19B2C406004C83CF /* InfoPlist.strings */, FB290CFF19B2C406004C83CF /* main.m */, @@ -551,7 +577,7 @@ 988FCD3F293B091B003050E2 /* KeyboardInputField.h */, 988FCD40293B091B003050E2 /* KeyboardInputField.m */, 84E1CDEB2C4F67D300547904 /* CommandManager.swift */, - 84203F222C5F24C00032EEED /* OnScreenButtonView.swift */, + 84203F222C5F24C00032EEED /* OnScreenWidgetView.swift */, ); path = Input; sourceTree = ""; @@ -815,6 +841,7 @@ FB89463819F6473800339C8A /* Launch Screen.xib in Resources */, 8454AC662C31907F00F0A302 /* iPad.storyboard in Resources */, 8454AC6A2C319BDA00F0A302 /* iPhone.storyboard in Resources */, + 843667F02D9D7173004A7D7F /* widgetTemplates.bin in Resources */, 84FD0B542C3134A6006B5BE5 /* Localizable.xcstrings in Resources */, 84351B5D2C29ADBE00A77989 /* ProfileTableViewCell.xib in Resources */, ); @@ -843,6 +870,7 @@ 843E93BE2C41528700B1651F /* OrientationHelper.swift in Sources */, FB4678FF1A565DAC00377732 /* WakeOnLanManager.m in Sources */, 84E1CDEC2C4F67D300547904 /* CommandManager.swift in Sources */, + 847D2FDB2DDA015F00937A62 /* MenuSectionView.m in Sources */, FB53E1431BE5DC4400CD6ECE /* IdManager.m in Sources */, 9897B6A1221260EF00966419 /* Controller.m in Sources */, 84351B112C29ACCB00A77989 /* OSCProfilesManager.m in Sources */, @@ -851,7 +879,7 @@ FBDE86E019F7A837001C18A8 /* UIComputerView.m in Sources */, FB89463019F646E200339C8A /* StreamConfiguration.m in Sources */, FBD3495319FF36FB002D2A60 /* SWRevealViewController.m in Sources */, - 84203F232C5F24C00032EEED /* OnScreenButtonView.swift in Sources */, + 84203F232C5F24C00032EEED /* OnScreenWidgetView.swift in Sources */, 84FD0B512C31338D006B5BE5 /* LocalizationHelper.m in Sources */, FB1D59971BBCCB6400F482CA /* ComputerScrollView.m in Sources */, FBD3495019FF2174002D2A60 /* SettingsViewController.m in Sources */, @@ -862,10 +890,12 @@ FB89462B19F646E200339C8A /* StreamView.m in Sources */, 840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */, FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */, + 841BAC922DE35D6B00DA639E /* UIColor+Theme.m in Sources */, 98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */, FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */, FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */, FB1D599A1BBCCD7E00F482CA /* AppCollectionView.m in Sources */, + 848F456A2DDCD12500581E36 /* HostCardView.m in Sources */, FB89463619F646E200339C8A /* StreamFrameViewController.m in Sources */, 9827E7A32514366900F25707 /* HapticContext.m in Sources */, 9832D1361BBCD5C50036EF48 /* TemporaryApp.m in Sources */,