Skip to content

Commit

Permalink
Add Appearance module
Browse files Browse the repository at this point in the history
Summary:
Android implementation of the Appearance native module. Exposes the user's preferred color scheme: "dark" for Night theme ON, "light" for Night theme OFF.

Emits a `appearanceChanged` event when the current uiMode configuration changes.

To make your app handle Night mode changes, make sure to do the following:

* Declare your Activity can handle uiMode configuration changes (https://developer.android.com/preview/features/darktheme#java):
```
android:configChanges="uiMode"
```
* Make sure to pass the configuration changed activity lifecycle callback from your ReactActivity:
```
Override
protected void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged();

    if (mReactInstanceManager != null) {
        mReactInstanceManager.onConfigurationChanged(newConfig);
    }
}
```

### RNTester

Adds the AppearanceExample to RNTester on Android.

Changelog:

[Android][Added] - New Appearance module exposes the user's current Night theme preference

Reviewed By: makovkastar

Differential Revision: D16942161

fbshipit-source-id: d24a8ff800a1c5f70f4efdec6891396c2078067e
  • Loading branch information
hramos authored and facebook-github-bot committed Aug 31, 2019
1 parent 51681e8 commit 17862a7
Show file tree
Hide file tree
Showing 11 changed files with 285 additions and 48 deletions.
4 changes: 2 additions & 2 deletions RNTester/android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def enableProguardInReleaseBuilds = true
def useIntlJsc = false

android {
compileSdkVersion 28
compileSdkVersion 29

compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
Expand All @@ -121,7 +121,7 @@ android {
defaultConfig {
applicationId "com.facebook.react.uiapp"
minSdkVersion 16
targetSdkVersion 28
targetSdkVersion 29
versionCode 1
versionName "1.0"
}
Expand Down
2 changes: 1 addition & 1 deletion RNTester/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
android:name=".RNTesterActivity"
android:label="@string/app_name"
android:screenOrientation="fullSensor"
android:configChanges="orientation|screenSize" >
android:configChanges="orientation|screenSize|uiMode" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@
*/
package com.facebook.react.uiapp;

import android.content.res.Configuration;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.facebook.react.ReactActivity;
import com.facebook.react.ReactActivityDelegate;
import com.facebook.react.ReactInstanceManager;

public class RNTesterActivity extends ReactActivity {
public static class RNTesterActivityDelegate extends ReactActivityDelegate {
Expand Down Expand Up @@ -53,4 +55,14 @@ protected ReactActivityDelegate createReactActivityDelegate() {
protected String getMainComponentName() {
return "RNTesterApp";
}

@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ReactInstanceManager instanceManager = getReactInstanceManager();

if (instanceManager != null) {
instanceManager.onConfigurationChanged(newConfig);
}
}
}
180 changes: 135 additions & 45 deletions RNTester/js/RNTesterApp.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@ const {
Text,
TouchableWithoutFeedback,
UIManager,
useColorScheme,
View,
} = require('react-native');

import type {RNTesterExample} from './types/RNTesterTypes';
import type {RNTesterNavigationState} from './utils/RNTesterNavigationReducer';
import {RNTesterThemeContext, themes} from './components/RNTesterTheme';

UIManager.setLayoutAnimationEnabledExperimental(true);

Expand All @@ -54,18 +57,119 @@ const HEADER_NAV_ICON = nativeImageSource({
height: 48,
});

const Header = ({title, onPressDrawer}) => {
const Header = ({
onPressDrawer,
title,
}: {
onPressDrawer?: () => mixed,
title: string,
}) => (
<RNTesterThemeContext.Consumer>
{theme => {
return (
<View style={[styles.toolbar, {backgroundColor: theme.ToolbarColor}]}>
<View style={styles.toolbarCenter}>
<Text style={[styles.title, {color: theme.LabelColor}]}>
{title}
</Text>
</View>
<View style={styles.toolbarLeft}>
<TouchableWithoutFeedback onPress={onPressDrawer}>
<Image source={HEADER_NAV_ICON} />
</TouchableWithoutFeedback>
</View>
</View>
);
}}
</RNTesterThemeContext.Consumer>
);

const RNTesterExampleContainerViaHook = ({
onPressDrawer,
title,
module,
exampleRef,
}: {
onPressDrawer?: () => mixed,
title: string,
module: RNTesterExample,
exampleRef: () => void,
}) => {
const colorScheme = useColorScheme();
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
return (
<View style={styles.toolbar}>
<View style={styles.toolbarCenter}>
<Text style={styles.title}>{title}</Text>
<RNTesterThemeContext.Provider value={theme}>
<View style={styles.container}>
<Header
title={title}
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
* was found when making Flow check .android.js files. */
onPressDrawer={onPressDrawer}
/>
<RNTesterExampleContainer module={module} ref={exampleRef} />
</View>
<View style={styles.toolbarLeft}>
<TouchableWithoutFeedback onPress={onPressDrawer}>
<Image source={HEADER_NAV_ICON} />
</TouchableWithoutFeedback>
</RNTesterThemeContext.Provider>
);
};

const RNTesterDrawerContentViaHook = ({
onNavigate,
list,
}: {
onNavigate?: () => mixed,
list: {
ComponentExamples: Array<RNTesterExample>,
APIExamples: Array<RNTesterExample>,
},
}) => {
const colorScheme = useColorScheme();
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
return (
<RNTesterThemeContext.Provider value={theme}>
<View
style={[
styles.drawerContentWrapper,
{backgroundColor: theme.SystemBackgroundColor},
]}>
<RNTesterExampleList
list={list}
displayTitleRow={true}
disableSearch={true}
onNavigate={onNavigate}
/>
</View>
</RNTesterThemeContext.Provider>
);
};

const RNTesterExampleListViaHook = ({
title,
onPressDrawer,
onNavigate,
list,
}: {
title: string,
onPressDrawer?: () => mixed,
onNavigate?: () => mixed,
list: {
ComponentExamples: Array<RNTesterExample>,
APIExamples: Array<RNTesterExample>,
},
}) => {
const colorScheme = useColorScheme();
const theme = colorScheme === 'dark' ? themes.dark : themes.light;
return (
<RNTesterThemeContext.Provider value={theme}>
<View style={styles.container}>
<Header
title={title}
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
* was found when making Flow check .android.js files. */
onPressDrawer={onPressDrawer}
/>
<RNTesterExampleList onNavigate={onNavigate} list={list} />
</View>
</View>
</RNTesterThemeContext.Provider>
);
};

Expand Down Expand Up @@ -133,14 +237,10 @@ class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {

_renderDrawerContent = () => {
return (
<View style={styles.drawerContentWrapper}>
<RNTesterExampleList
list={RNTesterList}
displayTitleRow={true}
disableSearch={true}
onNavigate={this._handleAction}
/>
</View>
<RNTesterDrawerContentViaHook
onNavigate={this._handleAction}
list={RNTesterList}
/>
);
};

Expand All @@ -164,39 +264,31 @@ class RNTesterApp extends React.Component<Props, RNTesterNavigationState> {
);
} else if (ExampleModule) {
return (
<View style={styles.container}>
<Header
title={ExampleModule.title}
<RNTesterExampleContainerViaHook
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
* when making Flow check .android.js files. */
onPressDrawer={() => this.drawer.openDrawer()}
title={ExampleModule.title}
module={ExampleModule}
exampleRef={example => {
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
* was found when making Flow check .android.js files. */
onPressDrawer={() => this.drawer.openDrawer()}
/>
<RNTesterExampleContainer
module={ExampleModule}
ref={example => {
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
* was found when making Flow check .android.js files. */
this._exampleRef = example;
}}
/>
</View>
this._exampleRef = example;
}}
/>
);
}
}

return (
<View style={styles.container}>
<Header
title="RNTester"
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue
* was found when making Flow check .android.js files. */
onPressDrawer={() => this.drawer.openDrawer()}
/>
<RNTesterExampleList
onNavigate={this._handleAction}
list={RNTesterList}
/>
</View>
<RNTesterExampleListViaHook
title={'RNTester'}
/* $FlowFixMe(>=0.78.0 site=react_native_android_fb) This issue was found
* when making Flow check .android.js files. */
onPressDrawer={() => this.drawer.openDrawer()}
onNavigate={this._handleAction}
list={RNTesterList}
/>
);
}

Expand Down Expand Up @@ -246,7 +338,6 @@ const styles = StyleSheet.create({
flex: 1,
},
toolbar: {
backgroundColor: '#E9EAED',
height: 56,
},
toolbarLeft: {
Expand All @@ -268,7 +359,6 @@ const styles = StyleSheet.create({
drawerContentWrapper: {
flex: 1,
paddingTop: StatusBar.currentHeight,
backgroundColor: 'white',
},
});

Expand Down
4 changes: 4 additions & 0 deletions RNTester/js/utils/RNTesterList.android.js
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ const APIExamples: Array<RNTesterExample> = [
key: 'AnimatedExample',
module: require('../examples/Animated/AnimatedExample'),
},
{
key: 'AppearanceExample',
module: require('../examples/Appearance/AppearanceExample'),
},
{
key: 'AppStateExample',
module: require('../examples/AppState/AppStateExample'),
Expand Down
1 change: 1 addition & 0 deletions ReactAndroid/src/main/java/com/facebook/react/BUCK
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ rn_android_library(
react_native_target("java/com/facebook/react/module/annotations:annotations"),
react_native_target("java/com/facebook/react/module/model:model"),
react_native_target("java/com/facebook/react/modules/appregistry:appregistry"),
react_native_target("java/com/facebook/react/modules/appearance:appearance"),
react_native_target("java/com/facebook/react/modules/core:core"),
react_native_target("java/com/facebook/react/modules/debug:debug"),
react_native_target("java/com/facebook/react/modules/fabric:fabric"),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Bundle;
import android.os.Process;
Expand Down Expand Up @@ -78,6 +79,7 @@
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
import com.facebook.react.devsupport.interfaces.DevSupportManager;
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
import com.facebook.react.modules.appearance.AppearanceModule;
import com.facebook.react.modules.appregistry.AppRegistry;
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
import com.facebook.react.modules.core.DeviceEventManagerModule;
Expand Down Expand Up @@ -712,6 +714,17 @@ public void onWindowFocusChange(boolean hasFocus) {
}
}

/** Call this from {@link Activity#onConfigurationChanged()}. */
@ThreadConfined(UI)
public void onConfigurationChanged(Configuration newConfig) {
UiThreadUtil.assertOnUiThread();

ReactContext currentContext = getCurrentReactContext();
if (currentContext != null) {
currentContext.getNativeModule(AppearanceModule.class).onConfigurationChanged();
}
}

@ThreadConfined(UI)
public void showDevOptionsDialog() {
UiThreadUtil.assertOnUiThread();
Expand Down
Loading

1 comment on commit 17862a7

@29er
Copy link

@29er 29er commented on 17862a7 Aug 31, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could this be the reason I cant run the RNTester app? .
I just downloaded about an hour ago.
It builds fine but does not run.
Throws error 'Unrecognized color scheme. did you mean dark or light ?'
was building for IOS however.....

Please sign in to comment.