//xplat/js/react-native-github/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/appearance:appearanceAndroid (#44006)

Summary:
Pull Request resolved: https://github.com/facebook/react-native/pull/44006

Changelog: [Internal]

Reviewed By: cortinico

Differential Revision: D55725334

fbshipit-source-id: 4d7ad2bb6395674d47fd5e3cd01a8515627f6cd4
This commit is contained in:
Andrew Datsenko
2024-04-10 07:45:57 -07:00
committed by Facebook GitHub Bot
parent b9a2249fff
commit c8d5f0f1aa
3 changed files with 109 additions and 128 deletions
@@ -2965,17 +2965,23 @@ public class com/facebook/react/modules/accessibilityinfo/AccessibilityInfoModul
public fun setAccessibilityFocus (D)V
}
public class com/facebook/react/modules/appearance/AppearanceModule : com/facebook/fbreact/specs/NativeAppearanceSpec {
public final class com/facebook/react/modules/appearance/AppearanceModule : com/facebook/fbreact/specs/NativeAppearanceSpec {
public static final field Companion Lcom/facebook/react/modules/appearance/AppearanceModule$Companion;
public static final field NAME Ljava/lang/String;
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;)V
public fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/modules/appearance/AppearanceModule$OverrideColorScheme;)V
public synthetic fun <init> (Lcom/facebook/react/bridge/ReactApplicationContext;Lcom/facebook/react/modules/appearance/AppearanceModule$OverrideColorScheme;ILkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun addListener (Ljava/lang/String;)V
public fun emitAppearanceChanged (Ljava/lang/String;)V
public final fun emitAppearanceChanged (Ljava/lang/String;)V
public fun getColorScheme ()Ljava/lang/String;
public fun onConfigurationChanged (Landroid/content/Context;)V
public final fun onConfigurationChanged (Landroid/content/Context;)V
public fun removeListeners (D)V
public fun setColorScheme (Ljava/lang/String;)V
}
public final class com/facebook/react/modules/appearance/AppearanceModule$Companion {
}
public abstract interface class com/facebook/react/modules/appearance/AppearanceModule$OverrideColorScheme {
public abstract fun getScheme ()Ljava/lang/String;
}
@@ -1,125 +0,0 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.appearance;
import android.app.Activity;
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;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.module.annotations.ReactModule;
/** Module that exposes the user's preferred color scheme. */
@ReactModule(name = NativeAppearanceSpec.NAME)
public class AppearanceModule extends NativeAppearanceSpec {
private static final String APPEARANCE_CHANGED_EVENT_NAME = "appearanceChanged";
private String mColorScheme = "light";
private final @Nullable OverrideColorScheme mOverrideColorScheme;
/** Optional override to the current color scheme */
public interface OverrideColorScheme {
/**
* Color scheme will use the return value instead of the current system configuration. Available
* scheme: {light, dark}
*/
public String getScheme();
}
public AppearanceModule(ReactApplicationContext reactContext) {
this(reactContext, null);
}
public AppearanceModule(
ReactApplicationContext reactContext, @Nullable OverrideColorScheme overrideColorScheme) {
super(reactContext);
mOverrideColorScheme = overrideColorScheme;
mColorScheme = colorSchemeForCurrentConfiguration(reactContext);
}
private String colorSchemeForCurrentConfiguration(Context context) {
if (mOverrideColorScheme != null) {
return mOverrideColorScheme.getScheme();
}
int currentNightMode =
context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK;
switch (currentNightMode) {
case Configuration.UI_MODE_NIGHT_NO:
return "light";
case Configuration.UI_MODE_NIGHT_YES:
return "dark";
}
return "light";
}
@Override
public void setColorScheme(String style) {
if (style.equals("dark")) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
} else if (style.equals("light")) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
} else if (style.equals("unspecified")) {
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
// scheme. This covers the scenario when AppCompatDelegate.setDefaultNightMode()
// is called directly (which can occur in Brownfield apps for example).
Activity activity = getCurrentActivity();
mColorScheme =
colorSchemeForCurrentConfiguration(
activity != null ? activity : getReactApplicationContext());
return mColorScheme;
}
/** Stub */
@Override
public void addListener(String eventName) {}
/** Stub */
@Override
public void removeListeners(double count) {}
/*
* Call this from your root activity whenever configuration changes. If the
* color scheme has changed, an event will emitted.
*/
public void onConfigurationChanged(Context currentContext) {
String newColorScheme = colorSchemeForCurrentConfiguration(currentContext);
if (!mColorScheme.equals(newColorScheme)) {
mColorScheme = newColorScheme;
emitAppearanceChanged(mColorScheme);
}
}
/** Sends an event to the JS instance that the preferred color scheme has changed. */
public void emitAppearanceChanged(String colorScheme) {
WritableMap appearancePreferences = Arguments.createMap();
appearancePreferences.putString("colorScheme", colorScheme);
ReactApplicationContext reactApplicationContext = getReactApplicationContextIfActiveOrWarn();
if (reactApplicationContext != null) {
reactApplicationContext.emitDeviceEvent(APPEARANCE_CHANGED_EVENT_NAME, appearancePreferences);
}
}
}
@@ -0,0 +1,100 @@
/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.modules.appearance
import android.content.Context
import android.content.res.Configuration
import androidx.appcompat.app.AppCompatDelegate
import com.facebook.fbreact.specs.NativeAppearanceSpec
import com.facebook.react.bridge.Arguments
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.module.annotations.ReactModule
/** Module that exposes the user's preferred color scheme. */
@ReactModule(name = NativeAppearanceSpec.NAME)
public class AppearanceModule
@JvmOverloads
constructor(
reactContext: ReactApplicationContext,
private val overrideColorScheme: OverrideColorScheme? = null
) : NativeAppearanceSpec(reactContext) {
private var colorScheme = colorSchemeForCurrentConfiguration(reactContext)
/** Optional override to the current color scheme */
public interface OverrideColorScheme {
/**
* Color scheme will use the return value instead of the current system configuration. Available
* scheme: {light, dark}
*/
public fun getScheme(): String
}
private fun colorSchemeForCurrentConfiguration(context: Context): String {
if (overrideColorScheme != null) {
return overrideColorScheme.getScheme()
}
val currentNightMode =
context.resources.configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
when (currentNightMode) {
Configuration.UI_MODE_NIGHT_NO -> return "light"
Configuration.UI_MODE_NIGHT_YES -> return "dark"
else -> return "light"
}
}
public override fun getColorScheme(): String {
// Attempt to use the Activity context first in order to get the most up to date
// scheme. This covers the scenario when AppCompatDelegate.setDefaultNightMode()
// is called directly (which can occur in Brownfield apps for example).
val activity = getCurrentActivity()
colorScheme = colorSchemeForCurrentConfiguration(activity ?: getReactApplicationContext())
return colorScheme
}
public override fun setColorScheme(style: String) {
when {
style == "dark" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES)
style == "light" -> AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO)
style == "unspecified" ->
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM)
}
}
/** Stub */
public override fun addListener(eventName: String): Unit = Unit
/** Stub */
public override fun removeListeners(count: Double): Unit = Unit
/*
* Call this from your root activity whenever configuration changes. If the
* color scheme has changed, an event will emitted.
*/
public fun onConfigurationChanged(currentContext: Context) {
val newColorScheme = colorSchemeForCurrentConfiguration(currentContext)
if (colorScheme != newColorScheme) {
colorScheme = newColorScheme
emitAppearanceChanged(colorScheme)
}
}
/** Sends an event to the JS instance that the preferred color scheme has changed. */
public fun emitAppearanceChanged(colorScheme: String) {
val appearancePreferences = Arguments.createMap()
appearancePreferences.putString("colorScheme", colorScheme)
val reactApplicationContext = getReactApplicationContextIfActiveOrWarn()
reactApplicationContext?.emitDeviceEvent(APPEARANCE_CHANGED_EVENT_NAME, appearancePreferences)
}
public companion object {
public const val NAME: String = NativeAppearanceSpec.NAME
private const val APPEARANCE_CHANGED_EVENT_NAME = "appearanceChanged"
}
}