1"use strict"; 2var __importDefault = (this && this.__importDefault) || function (mod) { 3 return (mod && mod.__esModule) ? mod : { "default": mod }; 4}; 5Object.defineProperty(exports, "__esModule", { value: true }); 6exports.setNavigationBarStyles = exports.setNavigationBarColors = exports.setStrings = exports.withAndroidNavigationBarExpoGoManifest = exports.resolveProps = void 0; 7// @ts-ignore: uses flow 8const normalize_color_1 = __importDefault(require("@react-native/normalize-color")); 9// @ts-ignore 10const debug_1 = __importDefault(require("debug")); 11const config_plugins_1 = require("expo/config-plugins"); 12const debug = (0, debug_1.default)('expo:system-navigation-bar:plugin'); 13const pkg = require('expo-navigation-bar/package.json'); 14// strings.xml keys, this should not change. 15const BORDER_COLOR_KEY = 'expo_navigation_bar_border_color'; 16const VISIBILITY_KEY = 'expo_navigation_bar_visibility'; 17const POSITION_KEY = 'expo_navigation_bar_position'; 18const BEHAVIOR_KEY = 'expo_navigation_bar_behavior'; 19const LEGACY_VISIBLE_KEY = 'expo_navigation_bar_legacy_visible'; 20// styles.xml value 21const NAVIGATION_BAR_COLOR = 'navigationBarColor'; 22const LEGACY_BAR_STYLE_MAP = { 23 // Match expo-status-bar 24 'dark-content': 'dark', 25 'light-content': 'light', 26}; 27function convertColorAndroid(input) { 28 let color = (0, normalize_color_1.default)(input); 29 if (!color) { 30 throw new Error('Invalid color value: ' + input); 31 } 32 color = ((color << 24) | (color >>> 8)) >>> 0; 33 // Android use 32 bit *signed* integer to represent the color 34 // We utilize the fact that bitwise operations in JS also operates on 35 // signed 32 bit integers, so that we can use those to convert from 36 // *unsigned* to *signed* 32bit int that way. 37 return color | 0x0; 38} 39function resolveProps(config, _props) { 40 let props; 41 if (!_props) { 42 props = { 43 backgroundColor: config.androidNavigationBar?.backgroundColor, 44 barStyle: config.androidNavigationBar?.barStyle 45 ? LEGACY_BAR_STYLE_MAP[config.androidNavigationBar?.barStyle] 46 : undefined, 47 // Resources for: 48 // - sticky-immersive: https://youtu.be/cBi8fjv90E4?t=416 -- https://developer.android.com/training/system-ui/immersive#sticky-immersive 49 // - immersive: https://youtu.be/cBi8fjv90E4?t=168 -- https://developer.android.com/training/system-ui/immersive#immersive 50 // - leanback: https://developer.android.com/training/system-ui/immersive#leanback 51 legacyVisible: config.androidNavigationBar?.visible, 52 }; 53 if (props.legacyVisible) { 54 // Using legacyVisible can break the setPositionAsync method: 55 // https://developer.android.com/reference/androidx/core/view/WindowCompat#setDecorFitsSystemWindows(android.view.Window,%20boolean) 56 config_plugins_1.WarningAggregator.addWarningAndroid('androidNavigationBar.visible', 'property is deprecated in Android 11 (API 30) and will be removed from Expo SDK', 'https://expo.fyi/android-navigation-bar-visible-deprecated'); 57 } 58 } 59 else { 60 props = _props; 61 } 62 return props; 63} 64exports.resolveProps = resolveProps; 65/** 66 * Ensure the Expo Go manifest is updated when the project is using config plugin properties instead 67 * of the static values that Expo Go reads from (`androidNavigationBar`). 68 */ 69const withAndroidNavigationBarExpoGoManifest = (config, props) => { 70 if (!config.androidNavigationBar) { 71 // Remap the config plugin props so Expo Go knows how to apply them. 72 config.androidNavigationBar = { 73 backgroundColor: props.backgroundColor ?? undefined, 74 barStyle: Object.entries(LEGACY_BAR_STYLE_MAP).find(([, v]) => v === props.barStyle)?.[0], 75 visible: props.legacyVisible, 76 }; 77 } 78 return config; 79}; 80exports.withAndroidNavigationBarExpoGoManifest = withAndroidNavigationBarExpoGoManifest; 81const withNavigationBar = (config, _props) => { 82 const props = resolveProps(config, _props); 83 config = (0, exports.withAndroidNavigationBarExpoGoManifest)(config, props); 84 debug('Props:', props); 85 // TODO: Add this to expo/config-plugins 86 // Elevate props to a static value on extra so Expo Go can read it. 87 if (!config.extra) { 88 config.extra = {}; 89 } 90 config.extra[pkg.name] = props; 91 // Use built-in styles instead of Expo custom properties, this makes the project hopefully a bit more predictable for bare users. 92 config = withNavigationBarColors(config, props); 93 config = withNavigationBarStyles(config, props); 94 return (0, config_plugins_1.withStringsXml)(config, (config) => { 95 config.modResults = setStrings(config.modResults, props); 96 return config; 97 }); 98}; 99function setStrings(strings, { borderColor, visibility, position, behavior, legacyVisible, }) { 100 const pairs = [ 101 [BORDER_COLOR_KEY, borderColor ? convertColorAndroid(borderColor) : null], 102 [VISIBILITY_KEY, visibility], 103 [POSITION_KEY, position], 104 [BEHAVIOR_KEY, behavior], 105 [LEGACY_VISIBLE_KEY, legacyVisible], 106 ]; 107 const stringItems = []; 108 for (const [key, value] of pairs) { 109 if (value == null) { 110 // Since we're using custom strings, we can remove them for convenience between prebuilds. 111 strings = config_plugins_1.AndroidConfig.Strings.removeStringItem(key, strings); 112 } 113 else { 114 stringItems.push(config_plugins_1.AndroidConfig.Resources.buildResourceItem({ 115 name: key, 116 value: String(value), 117 translatable: false, 118 })); 119 } 120 } 121 return config_plugins_1.AndroidConfig.Strings.setStringItem(stringItems, strings); 122} 123exports.setStrings = setStrings; 124const withNavigationBarColors = (config, props) => { 125 return (0, config_plugins_1.withAndroidColors)(config, (config) => { 126 config.modResults = setNavigationBarColors(props, config.modResults); 127 return config; 128 }); 129}; 130const withNavigationBarStyles = (config, props) => { 131 return (0, config_plugins_1.withAndroidStyles)(config, (config) => { 132 config.modResults = setNavigationBarStyles(props, config.modResults); 133 return config; 134 }); 135}; 136function setNavigationBarColors({ backgroundColor }, colors) { 137 if (backgroundColor) { 138 colors = config_plugins_1.AndroidConfig.Colors.setColorItem(config_plugins_1.AndroidConfig.Resources.buildResourceItem({ 139 name: NAVIGATION_BAR_COLOR, 140 value: backgroundColor, 141 }), colors); 142 } 143 return colors; 144} 145exports.setNavigationBarColors = setNavigationBarColors; 146function setNavigationBarStyles({ backgroundColor, barStyle }, styles) { 147 styles = config_plugins_1.AndroidConfig.Styles.assignStylesValue(styles, { 148 add: !!backgroundColor, 149 parent: config_plugins_1.AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(), 150 name: `android:${NAVIGATION_BAR_COLOR}`, 151 value: `@color/${NAVIGATION_BAR_COLOR}`, 152 }); 153 styles = config_plugins_1.AndroidConfig.Styles.assignStylesValue(styles, { 154 // Adding means the buttons will be darker to account for a light background color. 155 // `setButtonStyleAsync('dark')` should do the same thing. 156 add: barStyle === 'dark', 157 parent: config_plugins_1.AndroidConfig.Styles.getAppThemeLightNoActionBarGroup(), 158 name: 'android:windowLightNavigationBar', 159 value: 'true', 160 }); 161 return styles; 162} 163exports.setNavigationBarStyles = setNavigationBarStyles; 164exports.default = (0, config_plugins_1.createRunOncePlugin)(withNavigationBar, pkg.name, pkg.version); 165