From ff8cb20caef1d50bc3d56842f2cf3b5e244c9f0c Mon Sep 17 00:00:00 2001 From: xzzpig Date: Wed, 30 Jul 2025 01:20:36 +0800 Subject: [PATCH] add support for dynamic theme update --- VoidLink/HostCardView.h | 2 +- VoidLink/HostCardView.m | 4 +- VoidLink/ThemeManager.h | 3 +- VoidLink/ThemeManager.m | 6 +++ .../HostCollectionViewController.h | 1 + .../HostCollectionViewController.m | 19 ++++++- .../ViewControllers/MainFrameViewController.m | 51 ++++++++++++++++--- .../ViewControllers/SWRevealViewController.m | 31 +++++++++-- .../ViewControllers/SettingsViewController.m | 10 +++- .../StreamFrameViewController.m | 19 +++++-- 10 files changed, 127 insertions(+), 19 deletions(-) diff --git a/VoidLink/HostCardView.h b/VoidLink/HostCardView.h index a7c903a2..d0a3aa2a 100644 --- a/VoidLink/HostCardView.h +++ b/VoidLink/HostCardView.h @@ -28,6 +28,6 @@ - (void)resizeBySizeFactor:(CGFloat)factor; - (id) initWithHost:(TemporaryHost*)host; - (id) initWithHost:(TemporaryHost*)host andSizeFactor:(CGFloat)sizeFactor; +- (void)updateTheme; @end - diff --git a/VoidLink/HostCardView.m b/VoidLink/HostCardView.m index ff4852e2..9b8eda2e 100644 --- a/VoidLink/HostCardView.m +++ b/VoidLink/HostCardView.m @@ -431,7 +431,7 @@ static const float REFRESH_CYCLE = 2.0f; _size = CGSizeMake(_widthConstraint.constant, _heightConstraint.constant); - [self updateTheme:ThemeManager.userInterfaceStyle]; + [self updateTheme]; } - (void)createBackgroundLayer{ @@ -469,7 +469,7 @@ static const float REFRESH_CYCLE = 2.0f; } -- (void)updateTheme:(UIUserInterfaceStyle)userIterfaceStyle{ +- (void)updateTheme { self.backgroundColor = [ThemeManager widgetBackgroundColor]; _hostNameLabel.textColor = [ThemeManager textColor]; [_appButton setTitleColor:[ThemeManager appPrimaryColor] forState:UIControlStateNormal]; diff --git a/VoidLink/ThemeManager.h b/VoidLink/ThemeManager.h index bf98928a..781727d2 100644 --- a/VoidLink/ThemeManager.h +++ b/VoidLink/ThemeManager.h @@ -8,6 +8,8 @@ #import +extern NSString * const ThemeDidChangeNotification; + @interface ThemeManager:NSObject @property (class, nonatomic, assign) UIUserInterfaceStyle userInterfaceStyle; @@ -23,4 +25,3 @@ + (UIColor *)textTintColorWithAlpha; @end - diff --git a/VoidLink/ThemeManager.m b/VoidLink/ThemeManager.m index c0bca8e1..7b1a1437 100644 --- a/VoidLink/ThemeManager.m +++ b/VoidLink/ThemeManager.m @@ -8,6 +8,8 @@ #import "ThemeManager.h" +NSString * const ThemeDidChangeNotification = @"ThemeDidChangeNotification"; + @implementation ThemeManager static UIUserInterfaceStyle _privateUserInterfaceStyle = UIUserInterfaceStyleUnspecified; @@ -34,8 +36,12 @@ static UIUserInterfaceStyle _userInterfaceStyle; } + (void)setUserInterfaceStyle:(UIUserInterfaceStyle)style { + if (_userInterfaceStyle == style) { + return; + } _privateUserInterfaceStyle = style; [ThemeManager getUIStyle]; + [[NSNotificationCenter defaultCenter] postNotificationName:ThemeDidChangeNotification object:nil]; } + (UIColor *)appBackgroundColor { diff --git a/VoidLink/ViewControllers/HostCollectionViewController.h b/VoidLink/ViewControllers/HostCollectionViewController.h index b8f90017..d3cd2c5f 100644 --- a/VoidLink/ViewControllers/HostCollectionViewController.h +++ b/VoidLink/ViewControllers/HostCollectionViewController.h @@ -28,6 +28,7 @@ /// 添加一个 item - (void)addHost:(TemporaryHost *)host; - (void)removeHost:(TemporaryHost *)host; +- (void)updateTheme; /// 移除最后一个 item(如果有) - (void)removeLastItem; diff --git a/VoidLink/ViewControllers/HostCollectionViewController.m b/VoidLink/ViewControllers/HostCollectionViewController.m index 54caed9c..8a3ddc26 100644 --- a/VoidLink/ViewControllers/HostCollectionViewController.m +++ b/VoidLink/ViewControllers/HostCollectionViewController.m @@ -100,13 +100,28 @@ static const CGFloat cellOffsetY = 20; return self; } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)updateTheme { + self.collectionView.backgroundColor = [ThemeManager appBackgroundColor]; + for (HostCell *cell in [self.collectionView visibleCells]) { + [cell.cardView updateTheme]; + } +} + - (void)viewDidLoad { [super viewDidLoad]; [self.collectionView registerClass:[HostCell class] forCellWithReuseIdentifier:@"HostCell"]; self.collectionView.alwaysBounceVertical = NO; self.collectionView.showsVerticalScrollIndicator = NO; - self.collectionView.backgroundColor = [ThemeManager appBackgroundColor]; - + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateTheme) + name:ThemeDidChangeNotification + object:nil]; + [self updateTheme]; } diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index d49bd450..0c88fe40 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -1481,10 +1481,45 @@ static NSMutableSet* hostList; [_upButton setAction:@selector(switchToHostView)]; } -- (void)viewDidLoad{ - [ThemeManager setUserInterfaceStyle:UIScreen.mainScreen.traitCollection.userInterfaceStyle]; +- (void)updateTheme { + self.view.backgroundColor = [ThemeManager appBackgroundColor]; + self.hostCollectionVC.view.backgroundColor = [ThemeManager appBackgroundColor]; + self.collectionView.backgroundColor = [ThemeManager appBackgroundColor]; + if (@available(iOS 13.0, *)) { + [navBarAppearanceStandard setValue:[ThemeManager appBackgroundColor] forKey:@"backgroundColor"]; + NSDictionary* titleTextAttributes = @{ + NSForegroundColorAttributeName: [ThemeManager textColor] + }; + [navBarAppearanceStandard setValue:titleTextAttributes forKey:@"titleTextAttributes"]; + } + + _settingsButton.tintColor = [ThemeManager appPrimaryColor]; + _upButton.tintColor = [ThemeManager appPrimaryColor]; + ((UIButton*)_addHostButton.customView).backgroundColor = [ThemeManager appPrimaryColor]; + ((UIButton*)_helpButton.customView).tintColor = [ThemeManager appPrimaryColor]; + + [self applyNavBarAppearance]; + [self updateTitle]; + if (hostViewTitleLabel) { + hostViewTitleLabel.textColor = [ThemeManager textColor]; + } + [self.hostCollectionVC updateTheme]; +} + +// Called when the system's theme (light/dark mode) changes +- (void)traitCollectionDidChange:(UITraitCollection *)previousTraitCollection { + [super traitCollectionDidChange:previousTraitCollection]; + if (@available(iOS 13.0, *)) { + if ([self.traitCollection hasDifferentColorAppearanceComparedToTraitCollection:previousTraitCollection]) { + [ThemeManager setUserInterfaceStyle:self.traitCollection.userInterfaceStyle]; + } + } +} + +- (void)viewDidLoad{ [super viewDidLoad]; + //[OrientationHelper updateOrientationToLandscape]; // self.navigationController.delegate = self; [[NSNotificationCenter defaultCenter] addObserver:self @@ -1800,6 +1835,11 @@ static NSMutableSet* hostList; { [super viewWillAppear:NO]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateTheme) + name:ThemeDidChangeNotification + object:nil]; + /* this makes background color works*/ if(!_settingsViewExpanded){ @@ -1819,13 +1859,12 @@ 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.hostCollectionVC.view.backgroundColor = [ThemeManager appBackgroundColor]; - self.collectionView.backgroundColor = [ThemeManager appBackgroundColor]; - + [self.view addSubview:self.collectionView]; [self initHostCollection]; if(!_enteredAppView) [self switchToHostView]; + + [self updateTheme]; } - (void)viewDidDisappear:(BOOL)animated diff --git a/VoidLink/ViewControllers/SWRevealViewController.m b/VoidLink/ViewControllers/SWRevealViewController.m index eb08e380..29f12681 100755 --- a/VoidLink/ViewControllers/SWRevealViewController.m +++ b/VoidLink/ViewControllers/SWRevealViewController.m @@ -837,9 +837,36 @@ const int FrontViewPositionNone = 0xff; } -- (void)viewDidLoad{ +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + +- (void)updateTheme { + _contentView.backgroundColor = [ThemeManager appBackgroundColor]; + _contentView.rearNavView.backgroundColor = [ThemeManager appBackgroundColor]; + _separatorLine.backgroundColor = [ThemeManager separatorColor]; + if (@available(iOS 13.0, *)) { + UINavigationBarAppearance *navBarAppearanceStandard = _dockedNavBar.standardAppearance; + navBarAppearanceStandard.backgroundColor = [ThemeManager appBackgroundColor]; + navBarAppearanceStandard.titleTextAttributes = @{ + NSForegroundColorAttributeName: [ThemeManager textColor] + }; + _dockedNavBar.standardAppearance = navBarAppearanceStandard; + _dockedNavBar.scrollEdgeAppearance = navBarAppearanceStandard; + } else { + _dockedNavBar.barTintColor = [ThemeManager appBackgroundColor]; + } +} + +- (void)viewDidLoad{ self.isStreaming = false; //init this flag + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateTheme) + name:ThemeDidChangeNotification + object:nil]; + [self updateTheme]; } - (void)viewDidAppear:(BOOL)animated @@ -2425,5 +2452,3 @@ NSString * const SWSegueRightIdentifier = @"sw_right"; //} // //@end - - diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index c45fc929..fe8995f4 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -1232,8 +1232,16 @@ BOOL isCustomResolution(CGSize res) { */ } +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (void)viewDidLoad { - //[self updateTheme]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateTheme) + name:ThemeDidChangeNotification + object:nil]; + settingStackWillBeRelocatedToLowestPosition = false; hiddenStacks = [[NSMutableSet alloc] init]; diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index 11b71d44..057afa03 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -490,6 +490,16 @@ } +- (void)updateTheme { + self.view.backgroundColor = [ThemeManager appBackgroundColor]; + _stageLabel.textColor = [[ThemeManager textColor] colorWithAlphaComponent:0.9]; + _spinner.color = [ThemeManager textColor]; +} + +- (void)dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; +} + - (void)viewDidLoad { @@ -501,6 +511,11 @@ [UIApplication sharedApplication].idleTimerDisabled = YES; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(updateTheme) + name:@"ThemeDidChangeNotification" + object:nil]; + _settings = [[[DataManager alloc] init] getSettings]; //StreamFrameViewController retrieve the settings here. _stageLabel = [[UILabel alloc] init]; @@ -631,9 +646,7 @@ _stageLabel.textColor = [UIColor systemGrayColor]; _spinner.color = [UIColor systemGrayColor]; - self.view.backgroundColor = [ThemeManager appBackgroundColor]; - _stageLabel.textColor = [[ThemeManager textColor] colorWithAlphaComponent:0.9]; - _spinner.color = [ThemeManager textColor]; + [self updateTheme]; [self.view addSubview:_stageLabel]; [self.view addSubview:_spinner];