From 6ae3beb2a59b9cfcb2fa14dd1069c889a31cced1 Mon Sep 17 00:00:00 2001 From: TrueZhuanjia Date: Sat, 31 May 2025 12:00:32 +0800 Subject: [PATCH] - hostCardButtonActionDelegate - better theme color management --- Limelight/HostCardView.h | 12 +- Limelight/HostCardView.m | 109 ++++++++----- .../Input/CustomOSC/LayoutOnScreenControls.m | 2 - Limelight/Input/StreamView.m | 1 + Limelight/Network/AppAssetManager.m | 4 +- Limelight/Network/AppAssetRetriever.m | 2 + Limelight/Stream/VideoDecoderRenderer.m | 2 + Limelight/ThemeManager.h | 25 +++ Limelight/ThemeManager.m | 154 ++++++++++++++++++ Limelight/UIAppView.m | 13 +- Limelight/UIColor+Theme.h | 28 ---- Limelight/UIColor+Theme.m | 71 -------- .../LayoutOnScreenControlsViewController.m | 1 + .../HostCollectionViewController.m | 37 ++++- .../ViewControllers/MainFrameViewController.h | 3 +- .../ViewControllers/MainFrameViewController.m | 154 ++++++++++++++++-- Moonlight.xcodeproj/project.pbxproj | 12 +- 17 files changed, 449 insertions(+), 181 deletions(-) create mode 100644 Limelight/ThemeManager.h create mode 100644 Limelight/ThemeManager.m delete mode 100644 Limelight/UIColor+Theme.h delete mode 100644 Limelight/UIColor+Theme.m diff --git a/Limelight/HostCardView.h b/Limelight/HostCardView.h index 5d25df99..396dbf7b 100644 --- a/Limelight/HostCardView.h +++ b/Limelight/HostCardView.h @@ -10,18 +10,18 @@ #import #import "TemporaryHost.h" -@protocol HostCallback - -- (void) hostClicked:(TemporaryHost*)host view:(UIView*)view; -- (void) hostLongClicked:(TemporaryHost*)host view:(UIView*)view; -- (void) addHostClicked; +@protocol HostCardButtonActionDelegate +- (void)leftButtonTappedForHost:(TemporaryHost *)host; +- (void)rightButtonTappedForHost:(TemporaryHost *)host; +- (void)pairButtonTappedForHost:(TemporaryHost *)host; @end + @interface HostCardView : UIView @property (nonatomic, assign) CGFloat sizeFactor; @property (nonatomic, readonly) CGSize size; - +@property (nonatomic, weak) id delegate; // Delegate property - (void)resizeBySizeFactor:(CGFloat)factor; - (id) initWithHost:(TemporaryHost*)host; diff --git a/Limelight/HostCardView.m b/Limelight/HostCardView.m index 2305bdf4..93d28370 100644 --- a/Limelight/HostCardView.m +++ b/Limelight/HostCardView.m @@ -8,7 +8,7 @@ #import "HostCardView.h" #import "LocalizationHelper.h" -#import "UIColor+Theme.h" +#import "ThemeManager.h" @interface HostCardView () @@ -25,7 +25,6 @@ @property (nonatomic, strong) NSLayoutConstraint *heightConstraint; @property (nonatomic, strong) UIView *separatorLine; @property (nonatomic, assign) CGFloat cardContentpadding; -@property (nonatomic, assign) UIUserInterfaceStyle userIterfaceStyle; @property (nonatomic, assign) CGSize size; @@ -34,7 +33,6 @@ @implementation HostCardView { TemporaryHost* _host; - id _callback; UIActivityIndicatorView* _hostSpinner; UIImageView* lockIconView; CGFloat computerIconMonitorCenterYOffset; @@ -55,9 +53,8 @@ static const float REFRESH_CYCLE = 2.0f; computerIconMonitorCenterYOffset = -3.3*_sizeFactor; iconAndButtonSpacing = 37*_sizeFactor; buttonHeight = 40*_sizeFactor; - defaultBlue = [UIColor appPrimaryColor]; + defaultBlue = [ThemeManager 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]; @@ -86,7 +83,6 @@ static const float REFRESH_CYCLE = 2.0f; } - - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { @@ -95,6 +91,28 @@ static const float REFRESH_CYCLE = 2.0f; return self; } +- (void)leftButtonTapped{ + NSLog(@"self.delegate: %lu", (uintptr_t)self.delegate); + if ([self.delegate respondsToSelector:@selector(leftButtonTappedForHost:)]) { + [self.delegate leftButtonTappedForHost:_host]; + } else NSLog(@"Delegate not set or does not respond to leftButtonTappedForHost:"); +} + +- (void)rightButtonTapped{ + if ([self.delegate respondsToSelector:@selector(rightButtonTappedForHost:)]) { + [self.delegate rightButtonTappedForHost:_host]; + } else NSLog(@"Delegate not set or does not respond to rightButtonTappedForHost:"); +} + +-(void)pairButtonTapped{ + NSLog(@"pairButtonTapped testtestttttt"); + + if ([self.delegate respondsToSelector:@selector(pairButtonTappedForHost:)]) { + [self.delegate pairButtonTappedForHost:_host]; + } else NSLog(@"Delegate not set or does not respond to rightButtonTappedForHost:"); + +} + - (void)resizeBySizeFactor:(CGFloat)factor{ [self.subviews makeObjectsPerformSelector:@selector(removeFromSuperview)]; self.sizeFactor = factor; @@ -102,7 +120,7 @@ static const float REFRESH_CYCLE = 2.0f; } - (void)setupUI { - self.backgroundColor = [UIColor widgetBackgroundColorDark]; // theme + self.backgroundColor = [ThemeManager widgetBackgroundColor]; // theme self.layer.cornerRadius = 16; self.cardContentpadding = 13 * _sizeFactor; self.clipsToBounds = YES; @@ -247,8 +265,9 @@ static const float REFRESH_CYCLE = 2.0f; 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 setTitleColor:[ThemeManager textColorGray] forState:UIControlStateNormal]; //theme self.leftButton.titleLabel.font = [UIFont systemFontOfSize:16*_sizeFactor]; + [self.leftButton addTarget:self action:@selector(leftButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:self.leftButton]; [NSLayoutConstraint activateConstraints:@[ [self.leftButton.leadingAnchor constraintEqualToAnchor:self.iconBackgroundView.leadingAnchor constant:0], @@ -268,9 +287,8 @@ static const float REFRESH_CYCLE = 2.0f; [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.rightButton addTarget:self action:@selector(rightButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:self.rightButton]; if (@available(iOS 13.0, *)) { UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:self.rightButton.frame.size.height/4*_sizeFactor]; @@ -280,9 +298,7 @@ static const float REFRESH_CYCLE = 2.0f; // Fallback on earlier versions } - [_rightButton addTarget:self action:@selector(buttonTapped) forControlEvents:UIControlEventTouchUpInside]; - - + [NSLayoutConstraint activateConstraints:@[ [self.rightButton.leadingAnchor constraintEqualToAnchor:self.leftButton.trailingAnchor constant:15*_sizeFactor], [self.rightButton.centerYAnchor constraintEqualToAnchor:self.leftButton.centerYAnchor constant:0], @@ -295,11 +311,12 @@ static const float REFRESH_CYCLE = 2.0f; self.pairButton = [UIButton buttonWithType:UIButtonTypeSystem]; self.pairButton.translatesAutoresizingMaskIntoConstraints = NO; self.pairButton.frame = CGRectMake(0, 0, 150, 50); - self.pairButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + self.pairButton.backgroundColor = [ThemeManager 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.pairButton addTarget:self action:@selector(pairButtonTapped) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:self.pairButton]; // self.launchButton.imageEdgeInsets = UIEdgeInsetsMake(0, -10, 0, 0); @@ -311,7 +328,7 @@ static const float REFRESH_CYCLE = 2.0f; } else { // Fallback on earlier versions } - _pairButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + _pairButton.backgroundColor = [ThemeManager appPrimaryColorWithAlpha]; [_pairButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme [NSLayoutConstraint activateConstraints:@[ @@ -346,7 +363,7 @@ static const float REFRESH_CYCLE = 2.0f; _size = CGSizeMake(_widthConstraint.constant, _heightConstraint.constant); // standard size: 261 * 184 - [self updateTheme:_userIterfaceStyle]; + [self updateTheme:ThemeManager.userInterfaceStyle]; // [self updateContentsForHost:_host]; // [self updateTheme:UIUserInterfaceStyleLight]; } @@ -355,7 +372,7 @@ static const float REFRESH_CYCLE = 2.0f; backgroundLayer = [CAGradientLayer layer]; UIColor *gradientColorDark = [UIColor colorWithRed:0.0 green:0.319 blue:0.64 alpha:1.0]; UIColor *gradientColorLight = [gradientColorDark colorWithAlphaComponent:0.52]; - CGColorRef gradientColorRef = _userIterfaceStyle == UIUserInterfaceStyleDark ? gradientColorDark.CGColor : gradientColorLight.CGColor; + CGColorRef gradientColorRef = ThemeManager.userInterfaceStyle == UIUserInterfaceStyleDark ? gradientColorDark.CGColor : gradientColorLight.CGColor; backgroundLayer.colors = @[ (__bridge id)[UIColor clearColor].CGColor, (__bridge id)[UIColor clearColor].CGColor, @@ -381,25 +398,34 @@ static const float REFRESH_CYCLE = 2.0f; - (void)updateTheme:(UIUserInterfaceStyle)userIterfaceStyle{ + self.backgroundColor = [ThemeManager widgetBackgroundColor]; + _hostNameLabel.textColor = [ThemeManager textColor]; + [_leftButton setTitleColor:[ThemeManager appPrimaryColor] forState:UIControlStateNormal]; + _separatorLine.backgroundColor = [ThemeManager separatorColor]; + backgroundLayer.hidden = NO; + + /* switch (userIterfaceStyle) { case UIUserInterfaceStyleDark: - _hostNameLabel.textColor = [UIColor textColorDark]; - [_leftButton setTitleColor:[UIColor appPrimaryColor] forState:UIControlStateNormal]; - _separatorLine.backgroundColor = [UIColor separatorColorDark]; + _hostNameLabel.textColor = [ThemeManager textColorDark]; + [_leftButton setTitleColor:[ThemeManager appPrimaryColor] forState:UIControlStateNormal]; + _separatorLine.backgroundColor = [ThemeManager separatorColorDark]; // [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - self.backgroundColor = [UIColor widgetBackgroundColorDark]; + //self.backgroundColor = [ThemeManager widgetBackgroundColorDark]; backgroundLayer.hidden = NO; break; case UIUserInterfaceStyleLight: - _hostNameLabel.textColor = [UIColor textColorLight]; - [_leftButton setTitleColor:[UIColor appPrimaryColor] forState:UIControlStateNormal]; - _separatorLine.backgroundColor = [UIColor separatorColorLight]; + _hostNameLabel.textColor = [ThemeManager textColorLight]; + [_leftButton setTitleColor:[ThemeManager appPrimaryColor] forState:UIControlStateNormal]; + _separatorLine.backgroundColor = [ThemeManager separatorColorLight]; // [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; - self.backgroundColor = [UIColor widgetBackgroundColorLight]; + // self.backgroundColor = [ThemeManager widgetBackgroundColorLight]; backgroundLayer.hidden = NO; break; default:break; + } + */ [self updateContentsForHost:_host]; } @@ -425,11 +451,6 @@ static const float REFRESH_CYCLE = 2.0f; } -- (void) buttonTapped { - NSLog(@"button test"); -} - - - (void) updateLoop { // Stop immediately if the view has been detached if (self.superview == nil) { @@ -489,7 +510,7 @@ static const float REFRESH_CYCLE = 2.0f; [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; // theme } else { - _iconBackgroundView.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + _iconBackgroundView.backgroundColor = [ThemeManager appPrimaryColorWithAlpha]; lockIconView.hidden = NO; [_leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Applications"] forState:UIControlStateNormal]; [_rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Launch"] forState:UIControlStateNormal]; @@ -508,7 +529,7 @@ static const float REFRESH_CYCLE = 2.0f; } else { // Fallback on earlier versions } - _rightButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + _rightButton.backgroundColor = [ThemeManager appPrimaryColorWithAlpha]; [_rightButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal]; // theme } @@ -517,16 +538,16 @@ static const float REFRESH_CYCLE = 2.0f; case StateOffline: [_hostSpinner stopAnimating]; // _iconBackgroundView.backgroundColor = _userIterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; - _iconBackgroundView.backgroundColor = _userIterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; - _statusLabel.textColor = [UIColor textColorGray]; + _iconBackgroundView.backgroundColor = [ThemeManager appBackgroundColor]; + _statusLabel.textColor = [ThemeManager textColorGray]; _statusLabel.text = @"Offline"; - _statusIcon.tintColor = [UIColor textColorGray]; + _statusIcon.tintColor = [ThemeManager textColorGray]; if (@available(iOS 13.0, *)) { _statusIcon.image = [UIImage systemImageNamed:@"exclamationmark.triangle.fill"]; } else { // Fallback on earlier versions } - _hostIconView.tintColor = [UIColor lowProfileGray]; + _hostIconView.tintColor = [ThemeManager lowProfileGray]; lockIconView.hidden = YES; [_leftButton setTitle:[LocalizationHelper localizedStringForKey:@"Test network"] forState:UIControlStateNormal]; [_rightButton setTitle:[LocalizationHelper localizedStringForKey:@" Wakeup"] forState:UIControlStateNormal]; @@ -546,7 +567,7 @@ static const float REFRESH_CYCLE = 2.0f; } else { // Fallback on earlier versions } - _rightButton.backgroundColor = [UIColor appPrimaryColorWithAlpha]; + _rightButton.backgroundColor = [ThemeManager appPrimaryColorWithAlpha]; [_rightButton setTitleColor:defaultBlue forState:UIControlStateNormal]; // theme break; @@ -554,10 +575,10 @@ static const float REFRESH_CYCLE = 2.0f; _hostSpinner.color = [UIColor whiteColor]; [_hostSpinner startAnimating]; // _iconBackgroundView.backgroundColor = _userIterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; - _iconBackgroundView.backgroundColor = [UIColor appPrimaryColorWithAlpha]; - _statusLabel.textColor = [UIColor textColorGray]; + _iconBackgroundView.backgroundColor = [ThemeManager appPrimaryColorWithAlpha]; + _statusLabel.textColor = [ThemeManager textColorGray]; _statusLabel.text = @"Detecting..."; - _statusIcon.tintColor = [UIColor textColorGray]; + _statusIcon.tintColor = [ThemeManager textColorGray]; if (@available(iOS 13.0, *)) { _statusIcon.image = [UIImage systemImageNamed:@"antenna.radiowaves.left.and.right"]; } else { @@ -575,17 +596,17 @@ static const float REFRESH_CYCLE = 2.0f; _pairButton.hidden = YES; - [_leftButton setTitleColor:[UIColor textColorGray] forState:UIControlStateNormal]; // theme + [_leftButton setTitleColor:[ThemeManager 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]; + UIImage *coloredImage = [templateImage imageWithTintColor:[ThemeManager 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 + _rightButton.backgroundColor = [[ThemeManager textColorGray] colorWithAlphaComponent:0.2]; + [_rightButton setTitleColor:[ThemeManager textColorGray] forState:UIControlStateNormal]; // theme break; diff --git a/Limelight/Input/CustomOSC/LayoutOnScreenControls.m b/Limelight/Input/CustomOSC/LayoutOnScreenControls.m index d2fe3e85..c0580033 100644 --- a/Limelight/Input/CustomOSC/LayoutOnScreenControls.m +++ b/Limelight/Input/CustomOSC/LayoutOnScreenControls.m @@ -340,6 +340,4 @@ - - @end diff --git a/Limelight/Input/StreamView.m b/Limelight/Input/StreamView.m index 36b41c9b..c4d1b05f 100644 --- a/Limelight/Input/StreamView.m +++ b/Limelight/Input/StreamView.m @@ -1219,6 +1219,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; LiSendScrollEvent(deltaZ); } + #if !TARGET_OS_TV - (BOOL)isMultipleTouchEnabled { return YES; diff --git a/Limelight/Network/AppAssetManager.m b/Limelight/Network/AppAssetManager.m index 4a6480df..c61c3e73 100644 --- a/Limelight/Network/AppAssetManager.m +++ b/Limelight/Network/AppAssetManager.m @@ -46,7 +46,9 @@ static const int MAX_REQUEST_COUNT = 4; - (void) retrieveAssetsFromHost:(TemporaryHost*)host { for (TemporaryApp* app in host.appList) { - if (![[NSFileManager defaultManager] fileExistsAtPath:[AppAssetManager boxArtPathForApp:app]]) { + // if (![[NSFileManager defaultManager] fileExistsAtPath:[AppAssetManager boxArtPathForApp:app]]) { + if (true) { + NSLog(@"retrieve appImage"); AppAssetRetriever* retriever = [[AppAssetRetriever alloc] init]; retriever.app = app; retriever.host = host; diff --git a/Limelight/Network/AppAssetRetriever.m b/Limelight/Network/AppAssetRetriever.m index 75580dbb..4cae4a23 100644 --- a/Limelight/Network/AppAssetRetriever.m +++ b/Limelight/Network/AppAssetRetriever.m @@ -26,6 +26,8 @@ static const int MAX_ATTEMPTS = 5; if (appAssetResp.data != nil) { NSString* boxArtPath = [AppAssetManager boxArtPathForApp:self.app]; + NSLog(@"appImage from host not nil for app: %@", boxArtPath); + [[NSFileManager defaultManager] createDirectoryAtPath:[boxArtPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil]; [appAssetResp.data writeToFile:boxArtPath atomically:NO]; break; diff --git a/Limelight/Stream/VideoDecoderRenderer.m b/Limelight/Stream/VideoDecoderRenderer.m index 9c019a9e..66c3ca0b 100644 --- a/Limelight/Stream/VideoDecoderRenderer.m +++ b/Limelight/Stream/VideoDecoderRenderer.m @@ -686,4 +686,6 @@ int DrSubmitDecodeUnit(PDECODE_UNIT decodeUnit); } } + + @end diff --git a/Limelight/ThemeManager.h b/Limelight/ThemeManager.h new file mode 100644 index 00000000..0ea5d073 --- /dev/null +++ b/Limelight/ThemeManager.h @@ -0,0 +1,25 @@ +// +// ThemeManager.h +// Moonlight-ZWM +// +// Created by True砖家 on 2025.5.25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + +#import + +@interface ThemeManager:NSObject + +@property (class, nonatomic, assign) UIUserInterfaceStyle userInterfaceStyle; ++ (UIColor *)appPrimaryColor; ++ (UIColor *)appSecondaryColor; ++ (UIColor *)appPrimaryColorWithAlpha; ++ (UIColor *)widgetBackgroundColor; ++ (UIColor *)appBackgroundColor; ++ (UIColor *)separatorColor; ++ (UIColor *)textColor; ++ (UIColor *)textColorGray; ++ (UIColor *)lowProfileGray; + +@end + diff --git a/Limelight/ThemeManager.m b/Limelight/ThemeManager.m new file mode 100644 index 00000000..f0a49e5b --- /dev/null +++ b/Limelight/ThemeManager.m @@ -0,0 +1,154 @@ +// +// ThemeManager.h +// Moonlight-ZWM +// +// Created by True砖家 on 2025.5.25. +// Copyright © 2025 True砖家 @ Bilibili. All rights reserved. +// + +#import "ThemeManager.h" + +@implementation ThemeManager + +static UIUserInterfaceStyle _userInterfaceStyle = UIUserInterfaceStyleLight; + ++ (UIUserInterfaceStyle)userInterfaceStyle { + return _userInterfaceStyle; +} + ++ (void)setUserInterfaceStyle:(UIUserInterfaceStyle)style { + _userInterfaceStyle = style; +} + ++ (UIColor *)appBackgroundColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) { + UIUserInterfaceStyle style = self.userInterfaceStyle; + if (style == UIUserInterfaceStyleUnspecified) { + // 跟随系统 + style = traitCollection.userInterfaceStyle; + } + switch (style) { + case UIUserInterfaceStyleLight: + return [UIColor colorWithRed:242.0/255.0 green:242.0/255.0 blue:247.0/255.0 alpha:1.0]; + case UIUserInterfaceStyleDark: + default: + return [UIColor colorWithRed:28.0/255.0 green:28.0/255.0 blue:30.0/255.0 alpha:1.0]; + } + }]; + } else { + switch (self.userInterfaceStyle) { + case UIUserInterfaceStyleLight: + return [UIColor colorWithRed:242.0/255.0 green:242.0/255.0 blue:247.0/255.0 alpha:1.0]; + case UIUserInterfaceStyleDark: + default: + return [UIColor colorWithRed:28.0/255.0 green:28.0/255.0 blue:30.0/255.0 alpha:1.0]; + } + } +} + + ++ (UIColor *)widgetBackgroundColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) { + UIUserInterfaceStyle style = self.userInterfaceStyle; + if (style == UIUserInterfaceStyleUnspecified) { + // 跟随系统 + style = traitCollection.userInterfaceStyle; + } + switch (style) { + case UIUserInterfaceStyleLight: + return [UIColor whiteColor]; + case UIUserInterfaceStyleDark: + default: + return [UIColor colorWithRed:44.0/255.0 green:44.0/255.0 blue:46.0/255.0 alpha:1.0]; + } + }]; + } else { + switch (self.userInterfaceStyle) { + case UIUserInterfaceStyleLight: + return [UIColor whiteColor]; + case UIUserInterfaceStyleDark: + default: + return [UIColor colorWithRed:44.0/255.0 green:44.0/255.0 blue:46.0/255.0 alpha:1.0]; + } + } +} + ++ (UIColor *)separatorColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) { + UIUserInterfaceStyle style = self.userInterfaceStyle; + if (style == UIUserInterfaceStyleUnspecified) { + // 跟随系统 + style = traitCollection.userInterfaceStyle; + } + switch (style) { + case UIUserInterfaceStyleLight: + return [UIColor colorWithWhite:0.1 alpha:0.28]; + case UIUserInterfaceStyleDark: + default: + return [UIColor colorWithWhite:0.28 alpha:1.0]; + } + }]; + } else { + switch (self.userInterfaceStyle) { + case UIUserInterfaceStyleLight: + return [UIColor colorWithWhite:0.1 alpha:0.28]; + case UIUserInterfaceStyleDark: + default: + return [UIColor colorWithWhite:0.28 alpha:1.0]; + } + } +} + + ++ (UIColor *)textColor { + if (@available(iOS 13.0, *)) { + return [UIColor colorWithDynamicProvider:^UIColor *(UITraitCollection *traitCollection) { + UIUserInterfaceStyle style = self.userInterfaceStyle; + if (style == UIUserInterfaceStyleUnspecified) { + // 跟随系统 + style = traitCollection.userInterfaceStyle; + } + switch (style) { + case UIUserInterfaceStyleLight: + return [UIColor blackColor]; + case UIUserInterfaceStyleDark: + default: + return [UIColor whiteColor]; + } + }]; + } else { + switch (self.userInterfaceStyle) { + case UIUserInterfaceStyleLight: + return [UIColor blackColor]; + case UIUserInterfaceStyleDark: + default: + return [UIColor whiteColor]; + } + } +} + ++ (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 [[ThemeManager appPrimaryColor] colorWithAlphaComponent:0.24]; // #0A84FF +} + ++ (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]; +} + + +@end diff --git a/Limelight/UIAppView.m b/Limelight/UIAppView.m index 6ad9cf48..961d79c4 100644 --- a/Limelight/UIAppView.m +++ b/Limelight/UIAppView.m @@ -115,6 +115,7 @@ static UIImage* noImage; #endif - (void) updateAppImage { + if (_appOverlay != nil) { [_appOverlay removeFromSuperview]; _appOverlay = nil; @@ -128,6 +129,7 @@ static UIImage* noImage; // First check the memory cache UIImage* appImage = [_artCache objectForKey:_app]; + // NSLog(@"appImage instance: %lu", (uintptr_t)appImage); if (appImage == nil) { // Next try to load from the on disk cache appImage = [UIImage imageWithContentsOfFile:[AppAssetManager boxArtPathForApp:_app]]; @@ -135,12 +137,17 @@ static UIImage* noImage; [_artCache setObject:appImage forKey:_app]; } } - + // [_artCache setObject:appImage forKey:_app]; + 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)) { // GFE 3.0 + !(appImage.size.width == 628.f && appImage.size.height == 888.f)){ + + // if(true){ // GFE 3.0 [_appImage setImage:appImage]; } else { noAppImage = true; @@ -159,7 +166,7 @@ static UIImage* noImage; _appOverlay.contentMode = UIViewContentModeScaleAspectFit; } - if (noAppImage) { + if (true) { _appLabel = [[UILabel alloc] init]; [_appLabel setTextColor:[UIColor whiteColor]]; [_appLabel setText:_app.name]; diff --git a/Limelight/UIColor+Theme.h b/Limelight/UIColor+Theme.h deleted file mode 100644 index ea2120ef..00000000 --- a/Limelight/UIColor+Theme.h +++ /dev/null @@ -1,28 +0,0 @@ -// -// 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 deleted file mode 100644 index b7283174..00000000 --- a/Limelight/UIColor+Theme.m +++ /dev/null @@ -1,71 +0,0 @@ -// -// 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]; - return [UIColor whiteColor]; - -} - -+ (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]; - return [UIColor colorWithRed:242.0/255.0 green:242.0/255.0 blue:247.0/255.0 alpha:1.0]; - -} - - -@end diff --git a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m index b4dd9806..51973718 100644 --- a/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m +++ b/Limelight/ViewControllers/CustomOSCViewControl/LayoutOnScreenControlsViewController.m @@ -1069,4 +1069,5 @@ trashCanButton.tintColor = [UIColor colorWithRed:171.0/255.0 green:157.0/255.0 blue:255.0/255.0 alpha:1]; } + @end diff --git a/Limelight/ViewControllers/HostCollectionViewController.m b/Limelight/ViewControllers/HostCollectionViewController.m index 32b68d31..620cde00 100644 --- a/Limelight/ViewControllers/HostCollectionViewController.m +++ b/Limelight/ViewControllers/HostCollectionViewController.m @@ -9,11 +9,13 @@ #import "HostCollectionViewController.h" #import "HostCardView.h" #import "TemporaryHost.h" -#import "UIColor+Theme.h" +#import "ThemeManager.h" -@implementation HostCell +@implementation HostCell { + UIViewController* parentVC; +} - (void)prepareForReuse { [super prepareForReuse]; @@ -27,14 +29,34 @@ return self.contentView.bounds.size.height/dummyCard.size.height; } +- (UIViewController *)viewController { + UIResponder *responder = self; + while (responder) { + if ([responder isKindOfClass:[UIViewController class]]) { + return (UIViewController *)responder; + } + responder = responder.nextResponder; + } + return nil; +} + +- (void)assignDelegateForHostCard{ + parentVC = [self viewController].parentViewController; + if(parentVC != nil){ + if([parentVC conformsToProtocol:@protocol(HostCardButtonActionDelegate)]) self.cardView.delegate = (id) parentVC; + } +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + [self assignDelegateForHostCard]; +} - (void)configureWithHost:(TemporaryHost *)host { if (!self.cardView) { self.cardView = [[HostCardView alloc] initWithHost:host andSizeFactor:[self getHostCardSizeFactor]]; - // self.cardView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + [self assignDelegateForHostCard]; [self.contentView addSubview:self.cardView]; - NSLog(@"contentView width %f, %f", self.contentView.bounds.size.width, self.cardView.size.width); - [NSLayoutConstraint activateConstraints:@[ [self.cardView.leadingAnchor constraintEqualToAnchor:self.contentView.leadingAnchor], [self.cardView.topAnchor constraintEqualToAnchor:self.contentView.topAnchor], @@ -75,9 +97,11 @@ // Fallback on earlier versions } self.collectionView.alwaysBounceVertical = NO; - self.collectionView.backgroundColor = self.view.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; + self.collectionView.backgroundColor = [ThemeManager appBackgroundColor]; + } + #pragma mark - Data control - (void)viewDidAppear:(BOOL)animated { @@ -88,7 +112,6 @@ - (void)didMoveToParentViewController:(UIViewController *)parent { [super didMoveToParentViewController:parent]; NSLog(@"moved to parentVC: %@", parent); - // 可以在这里进行一些初始化,比如加载数据、刷新 UI 等 } diff --git a/Limelight/ViewControllers/MainFrameViewController.h b/Limelight/ViewControllers/MainFrameViewController.h index ee872f9e..2691b842 100644 --- a/Limelight/ViewControllers/MainFrameViewController.h +++ b/Limelight/ViewControllers/MainFrameViewController.h @@ -14,13 +14,14 @@ #import "PairManager.h" #import "StreamConfiguration.h" #import "UIComputerView.h" +#import "HostCardView.h" #import "UIAppView.h" #import "AppAssetManager.h" #import "SWRevealViewController.h" #import "HostCollectionViewController.h" -@interface MainFrameViewController : UICollectionViewController +@interface MainFrameViewController : UICollectionViewController @property (weak, nonatomic) IBOutlet UIBarButtonItem *settingsButton; #if !TARGET_OS_TV diff --git a/Limelight/ViewControllers/MainFrameViewController.m b/Limelight/ViewControllers/MainFrameViewController.m index 90c7915f..d10e755b 100644 --- a/Limelight/ViewControllers/MainFrameViewController.m +++ b/Limelight/ViewControllers/MainFrameViewController.m @@ -32,8 +32,7 @@ #import "LocalizationHelper.h" #import "CustomEdgeSlideGestureRecognizer.h" #import "DataManager.h" -#import "HostCardView.h" -#import "UIColor+Theme.h" +#import "ThemeManager.h" #import "Moonlight-Swift.h" // not used yet. #if !TARGET_OS_TV @@ -339,6 +338,133 @@ static NSMutableSet* hostList; [[self activeViewController] presentViewController:alert animated:YES completion:nil]; } +- (void)enterAppView{ + [self updateTitle]; + //_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 attachWaterMark]; + [self enableUpButton]; + [self disableNavigation]; + [self alreadyPaired]; +} + +- (void)leftButtonTappedForHost:(TemporaryHost *)host { + if (host.state != StateOnline) return; + _selectedHost = host; + if (host.state == StateOnline && host.pairState == PairStatePaired && host.appList.count > 0) { + [self enterAppView]; + } + +} + +- (void)rightButtonTappedForHost:(TemporaryHost *)host { + + _selectedHost = host; + if (host.state == StateOnline && host.pairState == PairStatePaired && host.appList.count > 0) { + [self enterAppView]; + [self updateAppsForHost:_selectedHost]; + [self prepareToStreamApp:_sortedAppList.firstObject]; + [self performSegueWithIdentifier:@"createStreamFrame" sender:nil]; + return; + } + + NSLog(@"wake testtttttt: hostName: %@, states: %d, %d", host.name, host.state, host.pairState); + + + if (host.state == StateOffline && host.pairState == PairStatePaired) { + UIAlertController* wolAlert = [UIAlertController alertControllerWithTitle:[LocalizationHelper localizedStringForKey:@"Wake-On-LAN"] message:@"" preferredStyle:UIAlertControllerStyleAlert]; + [wolAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Ok"] style:UIAlertActionStyleDefault handler:nil]]; + if (host.mac == nil || [host.mac isEqualToString:@"00:00:00:00:00:00"]) { + wolAlert.message = [LocalizationHelper localizedStringForKey: @"Host MAC unknown, unable to send WOL Packet"]; + } else { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [WakeOnLanManager wakeHost:host]; + }); + wolAlert.message = [LocalizationHelper localizedStringForKey:@"Successfully sent wake-up request. It may take a few moments for the PC to wake. If it never wakes up, ensure it's properly configured for Wake-on-LAN."]; + } + [[self activeViewController] presentViewController:wolAlert animated:YES completion:nil]; + } + + +} + +- (void)pairButtonTappedForHost:(TemporaryHost *)host{ + _selectedHost = host; + NSLog(@"pairButtonTappedForHost"); + [self showLoadingFrame: ^{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // Wait for the PC's status to be known + while (host.state == StateUnknown) { + sleep(1); + } + + // Don't bother polling if the server is already offline + if (host.state == StateOffline) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self hideLoadingFrame:^{ + [self showHostSelectionView]; + }]; + }); + return; + } + + HttpManager* hMan = [[HttpManager alloc] initWithHost:host]; + ServerInfoResponse* serverInfoResp = [[ServerInfoResponse alloc] init]; + + // Exempt this host from discovery while handling the serverinfo request + [self->_discMan pauseDiscoveryForHost:host]; + [hMan executeRequestSynchronously:[HttpRequest requestForResponse:serverInfoResp withUrlRequest:[hMan newServerInfoRequest:false] + fallbackError:401 fallbackRequest:[hMan newHttpServerInfoRequest]]]; + [self->_discMan resumeDiscoveryForHost:host]; + + if (![serverInfoResp isStatusOk]) { + Log(LOG_W, @"Failed to get server info: %@", serverInfoResp.statusMessage); + dispatch_async(dispatch_get_main_queue(), ^{ + if (host != self->_selectedHost) { + [self hideLoadingFrame:nil]; + return; + } + + UIAlertController* applistAlert = [UIAlertController alertControllerWithTitle:[LocalizationHelper localizedStringForKey:@"Connection Failed"] + message:serverInfoResp.statusMessage + preferredStyle:UIAlertControllerStyleAlert]; + [Utils addHelpOptionToDialog:applistAlert]; + [applistAlert addAction:[UIAlertAction actionWithTitle:[LocalizationHelper localizedStringForKey:@"Ok"] style:UIAlertActionStyleDefault handler:nil]]; + + // Only display an alert if this was the result of a real + // user action, not just passively entering the foreground again + [self hideLoadingFrame: ^{ + [self showHostSelectionView]; + [[self activeViewController] presentViewController:applistAlert animated:YES completion:nil]; + }]; + + host.state = StateOffline; + }); + } else { + // Update the host object with this data + [serverInfoResp populateHost:host]; + if (host.pairState == PairStatePaired) { + Log(LOG_I, @"Already Paired"); + [self alreadyPaired]; + } + // Only pair when this was the result of explicit user action + Log(LOG_I, @"Trying to pairTrying to pair"); + // Polling the server while pairing causes the server to screw up + [self->_discMan stopDiscoveryBlocking]; + PairManager* pMan = [[PairManager alloc] initWithManager:hMan clientCert:self->_clientCert callback:self]; + [self->_opQueue addOperation:pMan]; + + } + }); + }]; + + +} + + + - (void) hostClicked:(TemporaryHost *)host view:(UIView *)view { // Treat clicks on offline hosts to be long clicks // This shows the context menu with wake, delete, etc. rather @@ -373,7 +499,9 @@ static NSMutableSet* hostList; if (host.state == StateOnline && host.pairState == PairStatePaired && host.appList.count > 0 && view != nil) { [self alreadyPaired]; return; - } + } // 若已配对且在线, 该方法在此结束 + + // 若未在线或未配对, 有以下: [self showLoadingFrame: ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @@ -435,7 +563,7 @@ static NSMutableSet* hostList; } // Only pair when this was the result of explicit user action else if (view != nil) { - Log(LOG_I, @"Trying to pair"); + Log(LOG_I, @"Trying to pairTrying to pair"); // Polling the server while pairing causes the server to screw up [self->_discMan stopDiscoveryBlocking]; PairManager* pMan = [[PairManager alloc] initWithManager:hMan clientCert:self->_clientCert callback:self]; @@ -1229,8 +1357,6 @@ static NSMutableSet* hostList; if ([hostList count] == 1) [self hostClicked:[hostList anyObject] view:nil]; // auto click for single host - self.view.backgroundColor = self.view.traitCollection.userInterfaceStyle == UIUserInterfaceStyleDark ? [UIColor appBackgroundColorDark] : [UIColor appBackgroundColorLight]; - //if([SettingsViewController isLandscapeNow] != _streamConfig.width > _streamConfig.height) //[self simulateSettingsButtonPress]; //force expand setting view if orientation changed since last quit from app. @@ -1502,6 +1628,9 @@ static NSMutableSet* hostList; // this view via an error dialog from the stream // view, so we won't get a return to active notification // for that which would normally fire beginForegroundRefresh. + self.view.backgroundColor = [ThemeManager appBackgroundColor]; + + [self initHostCollection]; [self retrieveSavedHosts]; @@ -1602,8 +1731,7 @@ static NSMutableSet* hostList; // Sort the host list in alphabetical order NSArray* sortedHostList = [[hostList allObjects] sortedArrayUsingSelector:@selector(compareName:)]; for (TemporaryHost* comp in sortedHostList) { - - [self.hostCollectionVC addHost:comp]; + if(comp.state == StateOnline || comp.pairState == PairStatePaired) [self.hostCollectionVC addHost:comp]; compView = [[UIComputerView alloc] initWithComputer:comp andCallback:self]; // host view created here @@ -1832,13 +1960,14 @@ static NSMutableSet* hostList; #endif } + - (CGSize)getHostCardSize{ CGSize cardSize; 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); - // cardSize.width = + // cardSize.width = return cardSize; } @@ -1851,7 +1980,7 @@ static NSMutableSet* hostList; // 添加为子控制器 [self addChildViewController:self.hostCollectionVC]; [self.view addSubview:self.hostCollectionVC.view]; - + // 设置其布局(Auto Layout 示例) CGFloat hostCollectionViewPadding = 75; self.hostCollectionVC.view.translatesAutoresizingMaskIntoConstraints = NO; @@ -1861,10 +1990,11 @@ static NSMutableSet* hostList; [self.hostCollectionVC.view.trailingAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.trailingAnchor constant:-hostCollectionViewPadding], // [self.hostCollectionVC.view.bottomAnchor constraintEqualToAnchor:self.view.safeAreaLayoutGuide.bottomAnchor constant:0] //? ]]; - + // 通知子控制器已添加完成 [self.hostCollectionVC didMoveToParentViewController:self]; - + } + @end diff --git a/Moonlight.xcodeproj/project.pbxproj b/Moonlight.xcodeproj/project.pbxproj index e36b316d..50eb02b9 100644 --- a/Moonlight.xcodeproj/project.pbxproj +++ b/Moonlight.xcodeproj/project.pbxproj @@ -9,7 +9,7 @@ /* Begin PBXBuildFile section */ 189AD29A2DE7446000E24B88 /* HostCollectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 189AD2992DE7446000E24B88 /* HostCollectionViewController.m */; }; 840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */ = {isa = PBXBuildFile; fileRef = 840751B22BF49C050096B657 /* CustomTapGestureRecognizer.m */; }; - 841BAC922DE35D6B00DA639E /* UIColor+Theme.m in Sources */ = {isa = PBXBuildFile; fileRef = 841BAC912DE35D6B00DA639E /* UIColor+Theme.m */; }; + 841BAC922DE35D6B00DA639E /* ThemeManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 841BAC912DE35D6B00DA639E /* ThemeManager.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 */; }; @@ -134,8 +134,8 @@ 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 = ""; }; - 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 = ""; }; + 841BAC8F2DE35BEC00DA639E /* ThemeManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThemeManager.h; sourceTree = ""; }; + 841BAC912DE35D6B00DA639E /* ThemeManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ThemeManager.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 = ""; }; @@ -503,8 +503,8 @@ FB290D0319B2C406004C83CF /* AppDelegate.m */, 848F45682DDCD0D600581E36 /* HostCardView.h */, 848F45692DDCD12500581E36 /* HostCardView.m */, - 841BAC8F2DE35BEC00DA639E /* UIColor+Theme.h */, - 841BAC912DE35D6B00DA639E /* UIColor+Theme.m */, + 841BAC8F2DE35BEC00DA639E /* ThemeManager.h */, + 841BAC912DE35D6B00DA639E /* ThemeManager.m */, 847D2FD82DDA00C800937A62 /* MenuSectionView.h */, 847D2FDA2DDA015F00937A62 /* MenuSectionView.m */, FBDE86DE19F7A837001C18A8 /* UIComputerView.h */, @@ -896,7 +896,7 @@ FB89462B19F646E200339C8A /* StreamView.m in Sources */, 840751B32BF49C050096B657 /* CustomTapGestureRecognizer.m in Sources */, FB4678FA1A55FFAD00377732 /* DiscoveryManager.m in Sources */, - 841BAC922DE35D6B00DA639E /* UIColor+Theme.m in Sources */, + 841BAC922DE35D6B00DA639E /* ThemeManager.m in Sources */, 98D5856D1C0EA79600F6CC00 /* TemporaryHost.m in Sources */, FB89463519F646E200339C8A /* MainFrameViewController.m in Sources */, FBD1C8E21A8AD71400C6703C /* Logger.m in Sources */,