const { AndroidConfig, withAndroidColors, withAndroidColorsNight, withAndroidStyles, withAppBuildGradle, withDangerousMod, } = require('@expo/config-plugins'); const fs = require('fs'); const path = require('path'); const BUILD_TYPES_MARKER = '// @generated by with-android-customizations'; const BUILD_TYPES_APPLY = `${BUILD_TYPES_MARKER} apply from: new File( rootDir, "../plugins/android/android-build-types.gradle", ) `; const ANDROID_ASSET_VARIANTS = [ { source: 'release', target: 'main' }, { source: 'preview', target: 'preRelease' }, { source: 'debug', target: 'debug' }, ]; const LAUNCHER_RESOURCE_NAMES = [ 'ic_launcher', 'ic_launcher_background', 'ic_launcher_foreground', 'ic_launcher_monochrome', 'ic_launcher_round', ]; const DRAWABLE_RESOURCE_NAMES = [ 'notification_icon', 'splash_icon', 'splashscreen_logo', ]; const ANDROID_DENSITIES = ['mdpi', 'hdpi', 'xhdpi', 'xxhdpi', 'xxxhdpi']; /** * `AppTheme` inherits `android:windowBackground` from * `Theme.AppCompat.DayNight.NoActionBar`, which resolves to a near-white colour * whenever the system is in light mode. The window is visible for the frames * between the splash screen going away and React drawing its first frame, so * the app opens with a white flash for anyone using a dark theme on a light * system. These are the backgrounds of the default light and dark themes. */ const WINDOW_BACKGROUND_RESOURCE = 'lnreaderWindowBackground'; const WINDOW_BACKGROUND_LIGHT = '#FEFBFF'; const WINDOW_BACKGROUND_DARK = '#1B1B1F'; const withWindowBackgroundColors = config => { config = withAndroidColors(config, config => { config.modResults = AndroidConfig.Colors.assignColorValue( config.modResults, { name: WINDOW_BACKGROUND_RESOURCE, value: WINDOW_BACKGROUND_LIGHT }, ); return config; }); return withAndroidColorsNight(config, config => { config.modResults = AndroidConfig.Colors.assignColorValue( config.modResults, { name: WINDOW_BACKGROUND_RESOURCE, value: WINDOW_BACKGROUND_DARK }, ); return config; }); }; const withWindowBackgroundStyle = config => withAndroidStyles(config, config => { config.modResults = AndroidConfig.Styles.assignStylesValue( config.modResults, { add: true, parent: AndroidConfig.Styles.getAppThemeGroup(), name: 'android:windowBackground', value: `@color/${WINDOW_BACKGROUND_RESOURCE}`, }, ); return config; }); const withBuildGradleCustomizations = config => withAppBuildGradle(config, config => { const { contents } = config.modResults; if (!contents.includes(BUILD_TYPES_MARKER)) { config.modResults.contents = `${contents.trimEnd()} ${BUILD_TYPES_APPLY}`; } return config; }); const removeGeneratedIconResources = resDir => { if (!fs.existsSync(resDir)) { return; } for (const resourceDirName of fs.readdirSync(resDir)) { const resourceDir = path.join(resDir, resourceDirName); if (!fs.statSync(resourceDir).isDirectory()) { continue; } if (resourceDirName.startsWith('mipmap-')) { for (const resourceName of LAUNCHER_RESOURCE_NAMES) { for (const extension of ['png', 'webp', 'xml']) { fs.rmSync(path.join(resourceDir, `${resourceName}.${extension}`), { force: true, }); } } } if (resourceDirName.startsWith('drawable-')) { for (const resourceName of DRAWABLE_RESOURCE_NAMES) { for (const extension of ['png', 'webp', 'xml']) { fs.rmSync(path.join(resourceDir, `${resourceName}.${extension}`), { force: true, }); } } } } }; const installVariantSplashIcons = resDir => { for (const density of ANDROID_DENSITIES) { const drawableDir = path.join(resDir, `drawable-${density}`); const sourcePath = path.join(drawableDir, 'splash_icon.png'); const splashPath = path.join(drawableDir, 'splashscreen_logo.png'); const nightDrawableDir = path.join(resDir, `drawable-night-${density}`); const nightSplashPath = path.join( nightDrawableDir, 'splashscreen_logo.png', ); fs.renameSync(sourcePath, splashPath); fs.mkdirSync(nightDrawableDir, { recursive: true }); fs.copyFileSync(splashPath, nightSplashPath); } }; const withAndroidVariantAssets = config => withDangerousMod(config, [ 'android', config => { const { projectRoot, platformProjectRoot } = config.modRequest; for (const variant of ANDROID_ASSET_VARIANTS) { const sourceResDir = path.join( projectRoot, 'assets', 'android-icons', variant.source, 'res', ); const targetResDir = path.join( platformProjectRoot, 'app', 'src', variant.target, 'res', ); removeGeneratedIconResources(targetResDir); fs.mkdirSync(targetResDir, { recursive: true }); fs.cpSync(sourceResDir, targetResDir, { recursive: true }); installVariantSplashIcons(targetResDir); } return config; }, ]); module.exports = config => { config = withBuildGradleCustomizations(config); config = withWindowBackgroundColors(config); config = withWindowBackgroundStyle(config); return withAndroidVariantAssets(config); };