1082815dcSEvan Baconimport { ExpoConfig } from '@expo/config-types';
2082815dcSEvan Baconimport assert from 'assert';
3082815dcSEvan Bacon
4082815dcSEvan Baconimport { assignColorValue } from './Colors';
5082815dcSEvan Baconimport { ResourceXML } from './Resources';
6082815dcSEvan Baconimport { assignStylesValue, getAppThemeLightNoActionBarGroup } from './Styles';
7*8a424bebSJames Ideimport { ConfigPlugin } from '../Plugin.types';
8*8a424bebSJames Ideimport { withAndroidColors, withAndroidStyles } from '../plugins/android-plugins';
9082815dcSEvan Bacon
10082815dcSEvan Bacon// https://developer.android.com/reference/android/R.attr#colorPrimaryDark
11082815dcSEvan Baconconst COLOR_PRIMARY_DARK_KEY = 'colorPrimaryDark';
12082815dcSEvan Bacon// https://developer.android.com/reference/android/R.attr#windowTranslucentStatus
13082815dcSEvan Baconconst WINDOW_TRANSLUCENT_STATUS = 'android:windowTranslucentStatus';
14082815dcSEvan Bacon// https://developer.android.com/reference/android/R.attr#windowLightStatusBar
15082815dcSEvan Baconconst WINDOW_LIGHT_STATUS_BAR = 'android:windowLightStatusBar';
16082815dcSEvan Bacon
17082815dcSEvan Baconexport const withStatusBar: ConfigPlugin = (config) => {
18082815dcSEvan Bacon  config = withStatusBarColors(config);
19082815dcSEvan Bacon  config = withStatusBarStyles(config);
20082815dcSEvan Bacon  return config;
21082815dcSEvan Bacon};
22082815dcSEvan Bacon
23082815dcSEvan Baconconst withStatusBarColors: ConfigPlugin = (config) => {
24082815dcSEvan Bacon  return withAndroidColors(config, (config) => {
25082815dcSEvan Bacon    config.modResults = setStatusBarColors(config, config.modResults);
26082815dcSEvan Bacon    return config;
27082815dcSEvan Bacon  });
28082815dcSEvan Bacon};
29082815dcSEvan Bacon
30082815dcSEvan Baconconst withStatusBarStyles: ConfigPlugin = (config) => {
31082815dcSEvan Bacon  return withAndroidStyles(config, (config) => {
32082815dcSEvan Bacon    config.modResults = setStatusBarStyles(config, config.modResults);
33082815dcSEvan Bacon    return config;
34082815dcSEvan Bacon  });
35082815dcSEvan Bacon};
36082815dcSEvan Bacon
37082815dcSEvan Baconexport function setStatusBarColors(
38082815dcSEvan Bacon  config: Pick<ExpoConfig, 'androidStatusBar'>,
39082815dcSEvan Bacon  colors: ResourceXML
40082815dcSEvan Bacon): ResourceXML {
41082815dcSEvan Bacon  return assignColorValue(colors, {
42082815dcSEvan Bacon    name: COLOR_PRIMARY_DARK_KEY,
43082815dcSEvan Bacon    value: getStatusBarColor(config),
44082815dcSEvan Bacon  });
45082815dcSEvan Bacon}
46082815dcSEvan Bacon
47082815dcSEvan Baconexport function setStatusBarStyles(
48082815dcSEvan Bacon  config: Pick<ExpoConfig, 'androidStatusBar'>,
49082815dcSEvan Bacon  styles: ResourceXML
50082815dcSEvan Bacon): ResourceXML {
51082815dcSEvan Bacon  const hexString = getStatusBarColor(config);
52082815dcSEvan Bacon  const floatElement = getStatusBarTranslucent(config);
53082815dcSEvan Bacon
54082815dcSEvan Bacon  styles = assignStylesValue(styles, {
55082815dcSEvan Bacon    parent: getAppThemeLightNoActionBarGroup(),
56082815dcSEvan Bacon    name: WINDOW_LIGHT_STATUS_BAR,
57082815dcSEvan Bacon    targetApi: '23',
58082815dcSEvan Bacon    value: 'true',
59082815dcSEvan Bacon    // Default is light-content, don't need to do anything to set it
60082815dcSEvan Bacon    add: getStatusBarStyle(config) === 'dark-content',
61082815dcSEvan Bacon  });
62082815dcSEvan Bacon
63082815dcSEvan Bacon  styles = assignStylesValue(styles, {
64082815dcSEvan Bacon    parent: getAppThemeLightNoActionBarGroup(),
65082815dcSEvan Bacon    name: WINDOW_TRANSLUCENT_STATUS,
66082815dcSEvan Bacon    value: 'true',
67082815dcSEvan Bacon    // translucent status bar set in theme
68082815dcSEvan Bacon    add: floatElement,
69082815dcSEvan Bacon  });
70082815dcSEvan Bacon
71082815dcSEvan Bacon  styles = assignStylesValue(styles, {
72082815dcSEvan Bacon    parent: getAppThemeLightNoActionBarGroup(),
73082815dcSEvan Bacon    name: COLOR_PRIMARY_DARK_KEY,
74082815dcSEvan Bacon    value: `@color/${COLOR_PRIMARY_DARK_KEY}`,
75082815dcSEvan Bacon    // Remove the color if translucent is used
76082815dcSEvan Bacon    add: !!hexString,
77082815dcSEvan Bacon  });
78082815dcSEvan Bacon
79082815dcSEvan Bacon  return styles;
80082815dcSEvan Bacon}
81082815dcSEvan Bacon
82082815dcSEvan Baconexport function getStatusBarColor(config: Pick<ExpoConfig, 'androidStatusBar'>) {
83082815dcSEvan Bacon  const backgroundColor = config.androidStatusBar?.backgroundColor;
84082815dcSEvan Bacon  if (backgroundColor) {
85082815dcSEvan Bacon    // Drop support for translucent
86082815dcSEvan Bacon    assert(
87082815dcSEvan Bacon      backgroundColor !== 'translucent',
88082815dcSEvan Bacon      `androidStatusBar.backgroundColor must be a valid hex string, instead got: "${backgroundColor}"`
89082815dcSEvan Bacon    );
90082815dcSEvan Bacon  }
91082815dcSEvan Bacon  return backgroundColor;
92082815dcSEvan Bacon}
93082815dcSEvan Bacon
94082815dcSEvan Bacon/**
95082815dcSEvan Bacon * Specifies whether the status bar should be "translucent". When true, the status bar is drawn with `position: absolute` and a gray underlay, when false `position: relative` (pushes content down).
96082815dcSEvan Bacon *
97082815dcSEvan Bacon * @default false
98082815dcSEvan Bacon * @param config
99082815dcSEvan Bacon * @returns
100082815dcSEvan Bacon */
101082815dcSEvan Baconexport function getStatusBarTranslucent(config: Pick<ExpoConfig, 'androidStatusBar'>): boolean {
102082815dcSEvan Bacon  return config.androidStatusBar?.translucent ?? false;
103082815dcSEvan Bacon}
104082815dcSEvan Bacon
105082815dcSEvan Baconexport function getStatusBarStyle(config: Pick<ExpoConfig, 'androidStatusBar'>) {
106082815dcSEvan Bacon  return config.androidStatusBar?.barStyle || 'light-content';
107082815dcSEvan Bacon}
108