1import { ConfigPlugin, withMainActivity } from '@expo/config-plugins';
2import { addImports } from '@expo/config-plugins/build/android/codeMod';
3import { mergeContents, removeContents } from '@expo/config-plugins/build/utils/generateCode';
4import { ExpoConfig } from '@expo/config-types';
5import Debug from 'debug';
6
7import { getAndroidSplashConfig } from './getAndroidSplashConfig';
8
9const debug = Debug('expo:prebuild-config:expo-splash-screen:android:mainActivity');
10
11// DO NOT CHANGE
12const SHOW_SPLASH_ID = 'expo-splash-screen-mainActivity-onCreate-show-splash';
13
14export const withAndroidSplashLegacyMainActivity: ConfigPlugin = (config) => {
15  return withMainActivity(config, (config) => {
16    config.modResults.contents = setSplashScreenLegacyMainActivity(
17      config,
18      config.modResults.contents,
19      config.modResults.language
20    );
21    return config;
22  });
23};
24
25export function setSplashScreenLegacyMainActivity(
26  config: Pick<ExpoConfig, 'android' | 'androidStatusBar' | 'userInterfaceStyle'>,
27  mainActivity: string,
28  language: 'java' | 'kt'
29): string {
30  debug(`Modify with language: "${language}"`);
31  const splashConfig = getAndroidSplashConfig(config);
32
33  if (!splashConfig) {
34    // Remove our generated code safely...
35    const mod = removeContents({
36      src: mainActivity,
37      tag: SHOW_SPLASH_ID,
38    });
39
40    mainActivity = mod.contents;
41    if (mod.didClear) {
42      debug('Removed SplashScreen.show()');
43    }
44    return mainActivity;
45  }
46  // TODO: Translucent is weird
47  const statusBarTranslucent = !!config.androidStatusBar?.translucent;
48
49  const { resizeMode } = splashConfig;
50  const isJava = language === 'java';
51  const LE = isJava ? ';' : '';
52
53  mainActivity = addImports(
54    mainActivity,
55    [
56      'expo.modules.splashscreen.SplashScreen',
57      'expo.modules.splashscreen.SplashScreenImageResizeMode',
58      'android.os.Bundle',
59    ],
60    isJava
61  );
62
63  if (!mainActivity.match(/(?<=^.*super\.onCreate.*$)/m)) {
64    const onCreateBlock = isJava
65      ? [
66          '    @Override',
67          '    protected void onCreate(Bundle savedInstanceState) {',
68          '      super.onCreate(savedInstanceState);',
69          '    }',
70        ]
71      : [
72          '    override fun onCreate(savedInstanceState: Bundle?) {',
73          '      super.onCreate(savedInstanceState)',
74          '    }',
75        ];
76
77    mainActivity = mergeContents({
78      src: mainActivity,
79      // insert just below super.onCreate
80      anchor: isJava
81        ? /(?<=public\s+class\s+.*\s+extends\s+.*\s+{.*$)/m
82        : /(?<=class\s+.*\s+:\s+.*\s+{.*$)/m,
83      offset: 1,
84      comment: '//',
85      tag: 'expo-splash-screen-mainActivity-onCreate',
86      newSrc: onCreateBlock.join('\n'),
87    }).contents;
88  }
89
90  // Remove our generated code safely...
91  mainActivity = removeContents({
92    src: mainActivity,
93    tag: SHOW_SPLASH_ID,
94  }).contents;
95
96  // Remove code from `@expo/configure-splash-screen`
97  mainActivity = mainActivity
98    .split('\n')
99    .filter((line) => {
100      return !/SplashScreen\.show\(this,\s?SplashScreenImageResizeMode\./.test(line);
101    })
102    .join('\n');
103
104  // Reapply generated code.
105  mainActivity = mergeContents({
106    src: mainActivity,
107    // insert just below super.onCreate
108    anchor: /(?<=^.*super\.onCreate.*$)/m,
109    offset: 1,
110    comment: '//',
111    tag: SHOW_SPLASH_ID,
112    newSrc: `    SplashScreen.show(this, SplashScreenImageResizeMode.${resizeMode.toUpperCase()}, ReactRootView${
113      isJava ? '.class' : '::class.java'
114    }, ${statusBarTranslucent})${LE}`,
115  }).contents;
116
117  // TODO: Remove old `SplashScreen.show`
118
119  return mainActivity;
120}
121