1import {
2  AndroidConfig,
3  ConfigPlugin,
4  WarningAggregator,
5  withAndroidColors,
6  withAndroidStyles,
7} from '@expo/config-plugins';
8import { ExpoConfig } from '@expo/config-types';
9
10const NAVIGATION_BAR_COLOR = 'navigationBarColor';
11
12export const withNavigationBar: ConfigPlugin = (config) => {
13  const immersiveMode = getNavigationBarImmersiveMode(config);
14  if (immersiveMode) {
15    // Immersive mode needs to be set programmatically
16    WarningAggregator.addWarningAndroid(
17      'androidNavigationBar.visible',
18      'Property is deprecated in Android 11 (API 30) and will be removed from Expo SDK.',
19      'https://expo.fyi/android-navigation-bar-visible-deprecated'
20    );
21  }
22
23  config = withNavigationBarColors(config);
24  config = withNavigationBarStyles(config);
25  return config;
26};
27
28const withNavigationBarColors: ConfigPlugin = (config) => {
29  return withAndroidColors(config, (config) => {
30    config.modResults = setNavigationBarColors(config, config.modResults);
31    return config;
32  });
33};
34
35const withNavigationBarStyles: ConfigPlugin = (config) => {
36  return withAndroidStyles(config, (config) => {
37    config.modResults = setNavigationBarStyles(config, config.modResults);
38    return config;
39  });
40};
41
42export function setNavigationBarColors(
43  config: Pick<ExpoConfig, 'androidNavigationBar'>,
44  colors: AndroidConfig.Resources.ResourceXML
45): AndroidConfig.Resources.ResourceXML {
46  const hexString = getNavigationBarColor(config);
47  if (hexString) {
48    colors = AndroidConfig.Colors.setColorItem(
49      AndroidConfig.Resources.buildResourceItem({
50        name: NAVIGATION_BAR_COLOR,
51        value: hexString,
52      }),
53      colors
54    );
55  }
56  return colors;
57}
58
59export function setNavigationBarStyles(
60  config: Pick<ExpoConfig, 'androidNavigationBar'>,
61  styles: AndroidConfig.Resources.ResourceXML
62): AndroidConfig.Resources.ResourceXML {
63  styles = AndroidConfig.Styles.assignStylesValue(styles, {
64    add: getNavigationBarStyle(config) === 'dark-content',
65    parent: AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(),
66    name: 'android:windowLightNavigationBar',
67    value: 'true',
68  });
69  styles = AndroidConfig.Styles.assignStylesValue(styles, {
70    add: !!getNavigationBarColor(config),
71    parent: AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(),
72    name: `android:${NAVIGATION_BAR_COLOR}`,
73    value: `@color/${NAVIGATION_BAR_COLOR}`,
74  });
75
76  return styles;
77}
78
79export function getNavigationBarImmersiveMode(config: Pick<ExpoConfig, 'androidNavigationBar'>) {
80  return config.androidNavigationBar?.visible || null;
81}
82
83export function getNavigationBarColor(config: Pick<ExpoConfig, 'androidNavigationBar'>) {
84  return config.androidNavigationBar?.backgroundColor || null;
85}
86
87export function getNavigationBarStyle(config: Pick<ExpoConfig, 'androidNavigationBar'>) {
88  return config.androidNavigationBar?.barStyle || 'light-content';
89}
90