From 516b4a0edede82a5daacdb5445bf6f813155432d Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Fri, 27 Jan 2023 10:43:45 +0000 Subject: [PATCH 01/10] add setColorScheme support --- Libraries/Utilities/Appearance.d.ts | 8 ++++++ Libraries/Utilities/Appearance.js | 16 +++++++++++ Libraries/Utilities/NativeAppearance.js | 1 + React/CoreModules/RCTAppearance.h | 1 + React/CoreModules/RCTAppearance.mm | 28 +++++++++++++++++++ .../modules/appearance/AppearanceModule.java | 12 ++++++++ 6 files changed, 66 insertions(+) diff --git a/Libraries/Utilities/Appearance.d.ts b/Libraries/Utilities/Appearance.d.ts index 7d2faf69d8cec4..c4919602269de6 100644 --- a/Libraries/Utilities/Appearance.d.ts +++ b/Libraries/Utilities/Appearance.d.ts @@ -28,6 +28,14 @@ export namespace Appearance { */ export function getColorScheme(): ColorSchemeName; + /** + * Set the color scheme preference. This is useful for overriding the default + * color scheme preference for the app. Note that this will not change the + * appearance of the system UI, only the appearance of the app. + * Only available on iOS 13+ and Android 10+. + */ + export function setColorScheme(scheme: ColorSchemeName): void; + /** * Add an event handler that is fired when appearance preferences change. */ diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js index 54d03dd18200b2..c7de05d537c329 100644 --- a/Libraries/Utilities/Appearance.js +++ b/Libraries/Utilities/Appearance.js @@ -85,6 +85,22 @@ module.exports = { return nativeColorScheme; }, + setColorScheme(colorScheme: string): void { + const nativeColorScheme: ?string = + colorScheme == null ? 'unspecified' : colorScheme; + + invariant( + nativeColorScheme === 'dark' || + nativeColorScheme === 'light' || + nativeColorScheme == null, + "Unrecognized color scheme. Did you mean 'dark', 'light' or null?", + ); + + if (NativeAppearance != null) { + NativeAppearance.setColorScheme(nativeColorScheme); + } + }, + /** * Add an event handler that is fired when appearance preferences change. */ diff --git a/Libraries/Utilities/NativeAppearance.js b/Libraries/Utilities/NativeAppearance.js index cb8688f14e2967..af070c3e7067a9 100644 --- a/Libraries/Utilities/NativeAppearance.js +++ b/Libraries/Utilities/NativeAppearance.js @@ -26,6 +26,7 @@ export interface Spec extends TurboModule { // types. /* 'light' | 'dark' */ +getColorScheme: () => ?string; + +setColorScheme: (colorScheme: ?string) => void; // RCTEventEmitter +addListener: (eventName: string) => void; diff --git a/React/CoreModules/RCTAppearance.h b/React/CoreModules/RCTAppearance.h index d8bb18b89ac32b..36c36ebf15fc5f 100644 --- a/React/CoreModules/RCTAppearance.h +++ b/React/CoreModules/RCTAppearance.h @@ -7,6 +7,7 @@ #import +#import #import #import diff --git a/React/CoreModules/RCTAppearance.mm b/React/CoreModules/RCTAppearance.mm index 71259d4a98d119..0a1f3c3277d09f 100644 --- a/React/CoreModules/RCTAppearance.mm +++ b/React/CoreModules/RCTAppearance.mm @@ -68,6 +68,23 @@ void RCTOverrideAppearancePreference(NSString *const colorSchemeOverride) return RCTAppearanceColorSchemeLight; } +@implementation RCTConvert (UIUserInterfaceStyle) + +RCT_ENUM_CONVERTER( + UIUserInterfaceStyle, + (@{ + @"light" : @(UIUserInterfaceStyleLight), + @"dark" : @(UIUserInterfaceStyleDark), + @"unspecified" : @(UIUserInterfaceStyleUnspecified) + }), + UIUserInterfaceStyleUnspecified, + integerValue); + +@end + +@interface RCTAppearance () +@end + @interface RCTAppearance () @end @@ -92,6 +109,17 @@ - (dispatch_queue_t)methodQueue return std::make_shared(params); } +RCT_EXPORT_METHOD(setColorScheme : (NSString *)style) { + UIUserInterfaceStyle userInterfaceStyle = [RCTConvert UIUserInterfaceStyle:style]; + NSArray<__kindof UIWindow*>* windows = [[UIApplication sharedApplication] windows]; + if (@available(iOS 13.0, *)) { + for (UIWindow *window in windows) + { + window.overrideUserInterfaceStyle = userInterfaceStyle; + } + } +} + RCT_EXPORT_SYNCHRONOUS_TYPED_METHOD(NSString *, getColorScheme) { if (_currentColorScheme == nil) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java index e64bbe122c6df6..264e01512022f7 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java @@ -11,6 +11,7 @@ import android.content.Context; import android.content.res.Configuration; import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatDelegate; import com.facebook.fbreact.specs.NativeAppearanceSpec; import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.ReactApplicationContext; @@ -66,6 +67,17 @@ private String colorSchemeForCurrentConfiguration(Context context) { return "light"; } + @Override + public void setColorScheme(String style) { + if ("dark".equals(style)) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); + } else if ("light".equals(style)) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); + } else if ("unspecified".equals(style)) { + AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); + } + } + @Override public String getColorScheme() { // Attempt to use the Activity context first in order to get the most up to date From 6be233ad94c452eb2902234892cafd1f3aa13aa2 Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Fri, 27 Jan 2023 10:57:26 +0000 Subject: [PATCH 02/10] fix: duplicates --- React/CoreModules/RCTAppearance.mm | 3 --- 1 file changed, 3 deletions(-) diff --git a/React/CoreModules/RCTAppearance.mm b/React/CoreModules/RCTAppearance.mm index 0a1f3c3277d09f..23fbc98a09f35e 100644 --- a/React/CoreModules/RCTAppearance.mm +++ b/React/CoreModules/RCTAppearance.mm @@ -85,9 +85,6 @@ @implementation RCTConvert (UIUserInterfaceStyle) @interface RCTAppearance () @end -@interface RCTAppearance () -@end - @implementation RCTAppearance { NSString *_currentColorScheme; } From 1aa2118ff59ee39fb79b3e76e59ae424e6cd6665 Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Fri, 27 Jan 2023 11:32:12 +0000 Subject: [PATCH 03/10] add appcompat to buck --- .../src/main/java/com/facebook/react/modules/appearance/BUCK | 1 + ReactAndroid/src/main/java/com/facebook/react/shell/BUCK | 1 + 2 files changed, 2 insertions(+) diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK index 4cb4e081946767..044b4c8d0941a1 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/BUCK @@ -14,6 +14,7 @@ rn_android_library( deps = [ react_native_dep("third-party/java/jsr-305:jsr-305"), react_native_dep("third-party/android/androidx:annotation"), + react_native_dep("third-party/android/androidx:appcompat"), react_native_target("java/com/facebook/react/bridge:bridge"), react_native_target("java/com/facebook/react/common:common"), react_native_target("java/com/facebook/react/module/annotations:annotations"), diff --git a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK index b64122b9d3975e..5621dd31762a68 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK +++ b/ReactAndroid/src/main/java/com/facebook/react/shell/BUCK @@ -15,6 +15,7 @@ rn_android_library( react_native_dep("libraries/fresco/fresco-react-native:imagepipeline"), react_native_dep("libraries/soloader/java/com/facebook/soloader:soloader"), react_native_dep("third-party/android/androidx:annotation"), + react_native_dep("third-party/android/androidx:appcompat"), react_native_dep("third-party/android/androidx:core"), react_native_dep("third-party/android/androidx:fragment"), react_native_dep("third-party/android/androidx:legacy-support-core-utils"), From e6338766ad0ac3b647d2d6f33a1ab5e4b3c7ae2e Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Sun, 29 Jan 2023 16:03:01 +0000 Subject: [PATCH 04/10] fix: yoda and flow type --- Libraries/Utilities/Appearance.js | 2 +- .../facebook/react/modules/appearance/AppearanceModule.java | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js index c7de05d537c329..44ed36e1f934db 100644 --- a/Libraries/Utilities/Appearance.js +++ b/Libraries/Utilities/Appearance.js @@ -85,7 +85,7 @@ module.exports = { return nativeColorScheme; }, - setColorScheme(colorScheme: string): void { + setColorScheme(colorScheme: ?ColorSchemeName): void { const nativeColorScheme: ?string = colorScheme == null ? 'unspecified' : colorScheme; diff --git a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java index 264e01512022f7..301a8deff1bc05 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/modules/appearance/AppearanceModule.java @@ -69,11 +69,11 @@ private String colorSchemeForCurrentConfiguration(Context context) { @Override public void setColorScheme(String style) { - if ("dark".equals(style)) { + if (style == "dark") { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES); - } else if ("light".equals(style)) { + } else if (style == "light") { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); - } else if ("unspecified".equals(style)) { + } else if (style == "unspecified") { AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM); } } From c0c6068f166800382aa244da3c82ada322ebb1d1 Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Wed, 1 Feb 2023 09:50:23 +0000 Subject: [PATCH 05/10] Update Libraries/Utilities/Appearance.d.ts Co-authored-by: Nick Gerleman --- Libraries/Utilities/Appearance.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Utilities/Appearance.d.ts b/Libraries/Utilities/Appearance.d.ts index c4919602269de6..ed2a923193fa06 100644 --- a/Libraries/Utilities/Appearance.d.ts +++ b/Libraries/Utilities/Appearance.d.ts @@ -34,7 +34,7 @@ export namespace Appearance { * appearance of the system UI, only the appearance of the app. * Only available on iOS 13+ and Android 10+. */ - export function setColorScheme(scheme: ColorSchemeName): void; + export function setColorScheme(scheme: ColorSchemeName | null | undefined): void; /** * Add an event handler that is fired when appearance preferences change. From 38273e1db2f1c487d66c28606661cf25d579076c Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Wed, 1 Feb 2023 09:50:36 +0000 Subject: [PATCH 06/10] Update Libraries/Utilities/Appearance.js Co-authored-by: Nick Gerleman --- Libraries/Utilities/Appearance.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js index 44ed36e1f934db..bc105ffaeb85ec 100644 --- a/Libraries/Utilities/Appearance.js +++ b/Libraries/Utilities/Appearance.js @@ -90,9 +90,9 @@ module.exports = { colorScheme == null ? 'unspecified' : colorScheme; invariant( - nativeColorScheme === 'dark' || - nativeColorScheme === 'light' || - nativeColorScheme == null, + colorScheme === 'dark' || + colorScheme === 'light' || + colorScheme == null, "Unrecognized color scheme. Did you mean 'dark', 'light' or null?", ); From c923e82aaa65e9e17d8a409c8594c863c0389fa5 Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Wed, 1 Feb 2023 09:50:46 +0000 Subject: [PATCH 07/10] Update Libraries/Utilities/Appearance.js Co-authored-by: Nick Gerleman --- Libraries/Utilities/Appearance.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js index bc105ffaeb85ec..e65c82d8031313 100644 --- a/Libraries/Utilities/Appearance.js +++ b/Libraries/Utilities/Appearance.js @@ -86,7 +86,7 @@ module.exports = { }, setColorScheme(colorScheme: ?ColorSchemeName): void { - const nativeColorScheme: ?string = + const nativeColorScheme = colorScheme == null ? 'unspecified' : colorScheme; invariant( From eafc4c74ad84a0b662f0acee09531b1566fd7d7f Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Wed, 1 Feb 2023 09:54:18 +0000 Subject: [PATCH 08/10] fix: non-null and prettier --- Libraries/Utilities/Appearance.js | 7 ++----- Libraries/Utilities/NativeAppearance.js | 2 +- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Libraries/Utilities/Appearance.js b/Libraries/Utilities/Appearance.js index e65c82d8031313..485697c969fad2 100644 --- a/Libraries/Utilities/Appearance.js +++ b/Libraries/Utilities/Appearance.js @@ -86,13 +86,10 @@ module.exports = { }, setColorScheme(colorScheme: ?ColorSchemeName): void { - const nativeColorScheme = - colorScheme == null ? 'unspecified' : colorScheme; + const nativeColorScheme = colorScheme == null ? 'unspecified' : colorScheme; invariant( - colorScheme === 'dark' || - colorScheme === 'light' || - colorScheme == null, + colorScheme === 'dark' || colorScheme === 'light' || colorScheme == null, "Unrecognized color scheme. Did you mean 'dark', 'light' or null?", ); diff --git a/Libraries/Utilities/NativeAppearance.js b/Libraries/Utilities/NativeAppearance.js index af070c3e7067a9..98bf8ac7e62ba6 100644 --- a/Libraries/Utilities/NativeAppearance.js +++ b/Libraries/Utilities/NativeAppearance.js @@ -26,7 +26,7 @@ export interface Spec extends TurboModule { // types. /* 'light' | 'dark' */ +getColorScheme: () => ?string; - +setColorScheme: (colorScheme: ?string) => void; + +setColorScheme: (colorScheme: string) => void; // RCTEventEmitter +addListener: (eventName: string) => void; From 73aaf9b42495f68ffd44d4b1e558236d48429ac6 Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Wed, 1 Feb 2023 13:10:04 +0000 Subject: [PATCH 09/10] fix: prettier --- Libraries/Utilities/Appearance.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Libraries/Utilities/Appearance.d.ts b/Libraries/Utilities/Appearance.d.ts index ed2a923193fa06..2b8428e0d7d1de 100644 --- a/Libraries/Utilities/Appearance.d.ts +++ b/Libraries/Utilities/Appearance.d.ts @@ -34,7 +34,9 @@ export namespace Appearance { * appearance of the system UI, only the appearance of the app. * Only available on iOS 13+ and Android 10+. */ - export function setColorScheme(scheme: ColorSchemeName | null | undefined): void; + export function setColorScheme( + scheme: ColorSchemeName | null | undefined, + ): void; /** * Add an event handler that is fired when appearance preferences change. From b8f88763b988279d0ee8a0f93b6baba0565f775b Mon Sep 17 00:00:00 2001 From: Birkir Gudjonsson Date: Mon, 6 Feb 2023 23:00:32 +0000 Subject: [PATCH 10/10] fix: sharedApplication --- React/CoreModules/RCTAppearance.mm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/React/CoreModules/RCTAppearance.mm b/React/CoreModules/RCTAppearance.mm index 23fbc98a09f35e..5d93d6dd818491 100644 --- a/React/CoreModules/RCTAppearance.mm +++ b/React/CoreModules/RCTAppearance.mm @@ -10,6 +10,7 @@ #import #import #import +#import #import "CoreModulesPlugins.h" @@ -108,7 +109,7 @@ - (dispatch_queue_t)methodQueue RCT_EXPORT_METHOD(setColorScheme : (NSString *)style) { UIUserInterfaceStyle userInterfaceStyle = [RCTConvert UIUserInterfaceStyle:style]; - NSArray<__kindof UIWindow*>* windows = [[UIApplication sharedApplication] windows]; + NSArray<__kindof UIWindow*>* windows = RCTSharedApplication().windows; if (@available(iOS 13.0, *)) { for (UIWindow *window in windows) {