130 lines
6.1 KiB
JavaScript
130 lines
6.1 KiB
JavaScript
"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;
|
|
},
|
|
]);
|
|
}
|