mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
25a2c608f7
Summary: This PR fixes a few issues with the Appearance API (as noted here https://github.com/facebook/react-native/issues/28823). 1. For the Appearance API to work correctly on Android you need to call `AppearanceModule.onConfigurationChanged` when the current Activity goes through a configuration change. This was being called in the RNTester app but not in `ReactActivity` so it meant the Appearance API wouldn't work for Android in newly generated RN projects (or ones upgraded to the latest version of RN). 2. The Appearance API wasn't working correctly for brownfield scenarios on Android. It's possible to force an app light or dark natively on Android by calling `AppCompatDelegate.setDefaultNightMode()`. The Appearance API wasn't picking up changes from this function because it was using the Application context instead of the current Activity context. 3. The Appearance API wasn't working correctly for brownfield scenarios on iOS. Just like on Android its possible to force an app light or dark natively by setting `window.overrideUserInterfaceStyle`. The Appearance API didn't work with this override because we were overwriting `_currentColorScheme` back to default as soon as we set it. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> ### Fixed https://github.com/facebook/react-native/issues/28823 * [Android] [Fixed] - Appearance API now works on Android * [Android] [Fixed] - Appearance API now works correctly when calling `AppCompatDelegate.setDefaultNightMode()` * [iOS] [Fixed] - Appearance API now works correctly when setting `window.overrideUserInterfaceStyle` Pull Request resolved: https://github.com/facebook/react-native/pull/29106 Test Plan: Ran RNTester on iOS and Android and verified the Appearance examples still worked [correctly.](url) Reviewed By: hramos Differential Revision: D31284331 Pulled By: sota000 fbshipit-source-id: 45bbe33983e506eb177d596d33ddf15f846708fd
142 lines
3.7 KiB
Plaintext
142 lines
3.7 KiB
Plaintext
/*
|
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
#import "RCTAppearance.h"
|
|
|
|
#import <FBReactNativeSpec/FBReactNativeSpec.h>
|
|
#import <React/RCTConstants.h>
|
|
#import <React/RCTEventEmitter.h>
|
|
|
|
#import "CoreModulesPlugins.h"
|
|
|
|
using namespace facebook::react;
|
|
|
|
NSString *const RCTAppearanceColorSchemeLight = @"light";
|
|
NSString *const RCTAppearanceColorSchemeDark = @"dark";
|
|
|
|
static BOOL sAppearancePreferenceEnabled = YES;
|
|
void RCTEnableAppearancePreference(BOOL enabled)
|
|
{
|
|
sAppearancePreferenceEnabled = enabled;
|
|
}
|
|
|
|
static NSString *sColorSchemeOverride = nil;
|
|
void RCTOverrideAppearancePreference(NSString *const colorSchemeOverride)
|
|
{
|
|
sColorSchemeOverride = colorSchemeOverride;
|
|
}
|
|
|
|
NSString *RCTColorSchemePreference(UITraitCollection *traitCollection)
|
|
{
|
|
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && defined(__IPHONE_13_0) && \
|
|
__IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_13_0
|
|
if (@available(iOS 13.0, *)) {
|
|
static NSDictionary *appearances;
|
|
static dispatch_once_t onceToken;
|
|
|
|
if (sColorSchemeOverride) {
|
|
return sColorSchemeOverride;
|
|
}
|
|
|
|
dispatch_once(&onceToken, ^{
|
|
appearances = @{
|
|
@(UIUserInterfaceStyleLight) : RCTAppearanceColorSchemeLight,
|
|
@(UIUserInterfaceStyleDark) : RCTAppearanceColorSchemeDark
|
|
};
|
|
});
|
|
|
|
if (!sAppearancePreferenceEnabled) {
|
|
// Return the default if the app doesn't allow different color schemes.
|
|
return RCTAppearanceColorSchemeLight;
|
|
}
|
|
|
|
traitCollection = traitCollection ?: [UITraitCollection currentTraitCollection];
|
|
return appearances[@(traitCollection.userInterfaceStyle)] ?: RCTAppearanceColorSchemeLight;
|
|
}
|
|
#endif
|
|
|
|
// Default to light on older OS version - same behavior as Android.
|
|
return RCTAppearanceColorSchemeLight;
|
|
}
|
|
|
|
@interface RCTAppearance () <NativeAppearanceSpec>
|
|
@end
|
|
|
|
@implementation RCTAppearance {
|
|
NSString *_currentColorScheme;
|
|
}
|
|
|
|
RCT_EXPORT_MODULE(Appearance)
|
|
|
|
+ (BOOL)requiresMainQueueSetup
|
|
{
|
|
return YES;
|
|
}
|
|
|
|
- (dispatch_queue_t)methodQueue
|
|
{
|
|
return dispatch_get_main_queue();
|
|
}
|
|
|
|
- (std::shared_ptr<TurboModule>)getTurboModule:(const ObjCTurboModule::InitParams &)params
|
|
{
|
|
return std::make_shared<NativeAppearanceSpecJSI>(params);
|
|
}
|
|
|
|
RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme)
|
|
{
|
|
if (_currentColorScheme == nil) {
|
|
_currentColorScheme = RCTColorSchemePreference(nil);
|
|
}
|
|
return _currentColorScheme;
|
|
}
|
|
|
|
- (void)appearanceChanged:(NSNotification *)notification
|
|
{
|
|
NSDictionary *userInfo = [notification userInfo];
|
|
UITraitCollection *traitCollection = nil;
|
|
if (userInfo) {
|
|
traitCollection = userInfo[RCTUserInterfaceStyleDidChangeNotificationTraitCollectionKey];
|
|
}
|
|
NSString *newColorScheme = RCTColorSchemePreference(traitCollection);
|
|
if (![_currentColorScheme isEqualToString:newColorScheme]) {
|
|
_currentColorScheme = newColorScheme;
|
|
[self sendEventWithName:@"appearanceChanged" body:@{@"colorScheme" : newColorScheme}];
|
|
}
|
|
}
|
|
|
|
#pragma mark - RCTEventEmitter
|
|
|
|
- (NSArray<NSString *> *)supportedEvents
|
|
{
|
|
return @[ @"appearanceChanged" ];
|
|
}
|
|
|
|
- (void)startObserving
|
|
{
|
|
if (@available(iOS 13.0, *)) {
|
|
[[NSNotificationCenter defaultCenter] addObserver:self
|
|
selector:@selector(appearanceChanged:)
|
|
name:RCTUserInterfaceStyleDidChangeNotification
|
|
object:nil];
|
|
}
|
|
}
|
|
|
|
- (void)stopObserving
|
|
{
|
|
if (@available(iOS 13.0, *)) {
|
|
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
Class RCTAppearanceCls(void)
|
|
{
|
|
return RCTAppearance.class;
|
|
}
|