"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.withFontsAndroid = void 0; exports.groupByFamily = groupByFamily; exports.getXmlSpecs = getXmlSpecs; exports.generateFontManagerCalls = generateFontManagerCalls; const config_plugins_1 = require("expo/config-plugins"); const promises_1 = __importDefault(require("fs/promises")); const os_1 = __importDefault(require("os")); const path_1 = __importDefault(require("path")); const utils_1 = require("./utils"); const assetsFontsFir = 'app/src/main/assets/fonts'; const resourcesFontsDir = 'app/src/main/res/font'; const withFontsAndroid = (config, fonts) => { const assetFontPaths = fonts.filter((it) => typeof it === 'string'); config = copyFontsToDir(config, assetFontPaths, assetsFontsFir); const xmlFonts = fonts.filter((it) => typeof it === 'object'); config = addXmlFonts(config, xmlFonts); return config; }; exports.withFontsAndroid = withFontsAndroid; function groupByFamily(array) { return array.reduce((result, item) => { const keyValue = item['fontFamily']; result[keyValue] ||= []; result[keyValue].push(...item.fontDefinitions); return result; }, {}); } function addXmlFonts(config, xmlFontObjects) { const fontsByFamily = groupByFamily(xmlFontObjects); const fontPaths = Object.values(fontsByFamily) .map((font) => font.map((it) => it.path)) .flat(); config = copyFontsToDir(config, fontPaths, resourcesFontsDir, (filenameWithExt) => { const filename = (0, utils_1.toValidAndroidResourceName)(filenameWithExt); const ext = path_1.default.extname(filenameWithExt); return `${filename}${ext}`; }); config = addFontXmlToMainApplication(config, fontsByFamily); return (0, config_plugins_1.withDangerousMod)(config, [ 'android', async (config) => { const fontsDir = path_1.default.join(config.modRequest.platformProjectRoot, 'app/src/main/res/font'); const xmlSpecs = getXmlSpecs(fontsDir, fontsByFamily); await Promise.all(xmlSpecs.map(config_plugins_1.XML.writeXMLAsync)); return config; }, ]); } const resourceNameConflictAvoidancePrefix = 'xml_'; function getXmlSpecs(fontsDir, xmlFontObjects) { return Object.entries(xmlFontObjects).map(([fontFamily, fontDefinitions]) => { const filePath = path_1.default.join(fontsDir, `${resourceNameConflictAvoidancePrefix + (0, utils_1.toValidAndroidResourceName)(fontFamily)}.xml`); // each font family has one xml resource file with potentially multiple font definitions // the font files (e.g. ttf) at `path` are copied to res/font // with their name changed to be a valid resource and referenced in the xml file return { path: filePath, xml: { 'font-family': { // using `app` namespace for better compat: // https://developer.android.com/develop/ui/views/text-and-emoji/fonts-in-xml#using-support-lib $: { 'xmlns:app': 'http://schemas.android.com/apk/res-auto', }, font: fontDefinitions.map((definition) => { return { $: { 'app:font': `@font/${(0, utils_1.toValidAndroidResourceName)(definition.path)}`, 'app:fontStyle': definition.style || 'normal', 'app:fontWeight': String(definition.weight), }, }; }), }, }, }; }); } function addFontXmlToMainApplication(config, xmlFontObjects) { return (0, config_plugins_1.withMainApplication)(config, (config) => { const { modResults, modResults: { language }, } = config; modResults.contents = config_plugins_1.AndroidConfig.CodeMod.addImports(modResults.contents, ['com.facebook.react.common.assets.ReactFontManager'], language === 'java'); const fontManagerCalls = generateFontManagerCalls(xmlFontObjects, language).join(os_1.default.EOL); const withInit = config_plugins_1.CodeGenerator.mergeContents({ src: modResults.contents, comment: ' //', tag: 'xml-fonts-init', offset: 1, anchor: /super\.onCreate\(\)/, newSrc: fontManagerCalls, }); return { ...config, modResults: { ...modResults, contents: withInit.contents, }, }; }); } function generateFontManagerCalls(xmlFontObjects, language) { const lineEnding = language === 'java' ? ';' : ''; const indent = ' '; return Object.keys(xmlFontObjects).map((family) => `${indent}ReactFontManager.getInstance().addCustomFont(this, "${family}", R.font.${resourceNameConflictAvoidancePrefix + (0, utils_1.toValidAndroidResourceName)(family)})${lineEnding}`); } function copyFontsToDir(config, paths, inAppDestination, filenameProcessor = (filenameWithExt) => filenameWithExt) { return (0, config_plugins_1.withDangerousMod)(config, [ 'android', async (config) => { const fontsDir = path_1.default.join(config.modRequest.platformProjectRoot, inAppDestination); await promises_1.default.mkdir(fontsDir, { recursive: true }); const resolvedFonts = await (0, utils_1.resolveFontPaths)(paths, config.modRequest.projectRoot); await Promise.all(resolvedFonts.map(async (asset) => { const filenameWithExt = path_1.default.basename(asset); const outputFileName = filenameProcessor(filenameWithExt); const output = path_1.default.join(fontsDir, outputFileName); if (output.endsWith('.ttf') || output.endsWith('.otf')) { await promises_1.default.copyFile(asset, output); } })); return config; }, ]); }