1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.withNotificationsAndroid = exports.setNotificationSounds = exports.setNotificationIconColorAsync = exports.setNotificationIconAsync = exports.getNotificationColor = exports.getNotificationIcon = exports.withNotificationSounds = exports.withNotificationManifest = exports.withNotificationIconColor = exports.withNotificationIcons = exports.NOTIFICATION_ICON_COLOR_RESOURCE = exports.NOTIFICATION_ICON_COLOR = exports.NOTIFICATION_ICON_RESOURCE = exports.NOTIFICATION_ICON = exports.META_DATA_NOTIFICATION_ICON_COLOR = exports.META_DATA_NOTIFICATION_ICON = exports.dpiValues = exports.ANDROID_RES_PATH = void 0;
4const config_plugins_1 = require("@expo/config-plugins");
5const image_utils_1 = require("@expo/image-utils");
6const fs_1 = require("fs");
7const path_1 = require("path");
8const { buildResourceItem, readResourcesXMLAsync } = config_plugins_1.AndroidConfig.Resources;
9const { writeXMLAsync } = config_plugins_1.XML;
10const { Colors } = config_plugins_1.AndroidConfig;
11exports.ANDROID_RES_PATH = 'android/app/src/main/res/';
12exports.dpiValues = {
13    mdpi: { folderName: 'mipmap-mdpi', scale: 1 },
14    hdpi: { folderName: 'mipmap-hdpi', scale: 1.5 },
15    xhdpi: { folderName: 'mipmap-xhdpi', scale: 2 },
16    xxhdpi: { folderName: 'mipmap-xxhdpi', scale: 3 },
17    xxxhdpi: { folderName: 'mipmap-xxxhdpi', scale: 4 },
18};
19const { addMetaDataItemToMainApplication, getMainApplicationOrThrow, removeMetaDataItemFromMainApplication, } = config_plugins_1.AndroidConfig.Manifest;
20const BASELINE_PIXEL_SIZE = 24;
21const ERROR_MSG_PREFIX = 'An error occurred while configuring Android notifications. ';
22exports.META_DATA_NOTIFICATION_ICON = 'expo.modules.notifications.default_notification_icon';
23exports.META_DATA_NOTIFICATION_ICON_COLOR = 'expo.modules.notifications.default_notification_color';
24exports.NOTIFICATION_ICON = 'notification_icon';
25exports.NOTIFICATION_ICON_RESOURCE = `@drawable/${exports.NOTIFICATION_ICON}`;
26exports.NOTIFICATION_ICON_COLOR = 'notification_icon_color';
27exports.NOTIFICATION_ICON_COLOR_RESOURCE = `@color/${exports.NOTIFICATION_ICON_COLOR}`;
28exports.withNotificationIcons = (config, { icon }) => {
29    // If no icon provided in the config plugin props, fallback to value from app.json
30    icon = icon || getNotificationIcon(config);
31    return config_plugins_1.withDangerousMod(config, [
32        'android',
33        async (config) => {
34            await setNotificationIconAsync(config.modRequest.projectRoot, icon);
35            return config;
36        },
37    ]);
38};
39exports.withNotificationIconColor = (config, { color }) => {
40    // If no color provided in the config plugin props, fallback to value from app.json
41    color = color || getNotificationColor(config);
42    return config_plugins_1.withDangerousMod(config, [
43        'android',
44        async (config) => {
45            await setNotificationIconColorAsync(config.modRequest.projectRoot, color);
46            return config;
47        },
48    ]);
49};
50exports.withNotificationManifest = (config, { icon, color }) => {
51    // If no icon or color provided in the config plugin props, fallback to value from app.json
52    icon = icon || getNotificationIcon(config);
53    color = color || getNotificationColor(config);
54    return config_plugins_1.withAndroidManifest(config, config => {
55        config.modResults = setNotificationConfig({ icon, color }, config.modResults);
56        return config;
57    });
58};
59exports.withNotificationSounds = (config, { sounds }) => {
60    return config_plugins_1.withDangerousMod(config, [
61        'android',
62        config => {
63            setNotificationSounds(config.modRequest.projectRoot, sounds);
64            return config;
65        },
66    ]);
67};
68function getNotificationIcon(config) {
69    var _a;
70    return ((_a = config.notification) === null || _a === void 0 ? void 0 : _a.icon) || null;
71}
72exports.getNotificationIcon = getNotificationIcon;
73function getNotificationColor(config) {
74    var _a;
75    return ((_a = config.notification) === null || _a === void 0 ? void 0 : _a.color) || null;
76}
77exports.getNotificationColor = getNotificationColor;
78/**
79 * Applies notification icon configuration for expo-notifications
80 */
81async function setNotificationIconAsync(projectRoot, icon) {
82    if (icon) {
83        await writeNotificationIconImageFilesAsync(icon, projectRoot);
84    }
85    else {
86        removeNotificationIconImageFiles(projectRoot);
87    }
88}
89exports.setNotificationIconAsync = setNotificationIconAsync;
90function setNotificationConfig(props, manifest) {
91    const mainApplication = getMainApplicationOrThrow(manifest);
92    if (props.icon) {
93        addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON, exports.NOTIFICATION_ICON_RESOURCE, 'resource');
94    }
95    else {
96        removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON);
97    }
98    if (props.color) {
99        addMetaDataItemToMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON_COLOR, exports.NOTIFICATION_ICON_COLOR_RESOURCE, 'resource');
100    }
101    else {
102        removeMetaDataItemFromMainApplication(mainApplication, exports.META_DATA_NOTIFICATION_ICON_COLOR);
103    }
104    return manifest;
105}
106async function setNotificationIconColorAsync(projectRoot, color) {
107    const colorsXmlPath = await Colors.getProjectColorsXMLPathAsync(projectRoot);
108    let colorsJson = await readResourcesXMLAsync({ path: colorsXmlPath });
109    if (color) {
110        const colorItemToAdd = buildResourceItem({ name: exports.NOTIFICATION_ICON_COLOR, value: color });
111        colorsJson = Colors.setColorItem(colorItemToAdd, colorsJson);
112    }
113    else {
114        colorsJson = Colors.removeColorItem(exports.NOTIFICATION_ICON_COLOR, colorsJson);
115    }
116    await writeXMLAsync({ path: colorsXmlPath, xml: colorsJson });
117}
118exports.setNotificationIconColorAsync = setNotificationIconColorAsync;
119async function writeNotificationIconImageFilesAsync(icon, projectRoot) {
120    await Promise.all(Object.values(exports.dpiValues).map(async ({ folderName, scale }) => {
121        const drawableFolderName = folderName.replace('mipmap', 'drawable');
122        const dpiFolderPath = path_1.resolve(projectRoot, exports.ANDROID_RES_PATH, drawableFolderName);
123        if (!fs_1.existsSync(dpiFolderPath)) {
124            fs_1.mkdirSync(dpiFolderPath, { recursive: true });
125        }
126        const iconSizePx = BASELINE_PIXEL_SIZE * scale;
127        try {
128            const resizedIcon = (await image_utils_1.generateImageAsync({ projectRoot, cacheType: 'android-notification' }, {
129                src: icon,
130                width: iconSizePx,
131                height: iconSizePx,
132                resizeMode: 'cover',
133                backgroundColor: 'transparent',
134            })).source;
135            fs_1.writeFileSync(path_1.resolve(dpiFolderPath, exports.NOTIFICATION_ICON + '.png'), resizedIcon);
136        }
137        catch (e) {
138            throw new Error(ERROR_MSG_PREFIX + 'Encountered an issue resizing Android notification icon: ' + e);
139        }
140    }));
141}
142function removeNotificationIconImageFiles(projectRoot) {
143    Object.values(exports.dpiValues).forEach(async ({ folderName }) => {
144        const drawableFolderName = folderName.replace('mipmap', 'drawable');
145        const dpiFolderPath = path_1.resolve(projectRoot, exports.ANDROID_RES_PATH, drawableFolderName);
146        fs_1.unlinkSync(path_1.resolve(dpiFolderPath, exports.NOTIFICATION_ICON + '.png'));
147    });
148}
149/**
150 * Save sound files to `<project-root>/android/app/src/main/res/raw`
151 */
152function setNotificationSounds(projectRoot, sounds) {
153    if (!Array.isArray(sounds)) {
154        throw new Error(ERROR_MSG_PREFIX +
155            `Must provide an array of sound files in your app config, found ${typeof sounds}.`);
156    }
157    for (const soundFileRelativePath of sounds) {
158        writeNotificationSoundFile(soundFileRelativePath, projectRoot);
159    }
160}
161exports.setNotificationSounds = setNotificationSounds;
162/**
163 * Copies the input file to the `<project-root>/android/app/src/main/res/raw` directory if
164 * there isn't already an existing file under that name.
165 */
166function writeNotificationSoundFile(soundFileRelativePath, projectRoot) {
167    const rawResourcesPath = path_1.resolve(projectRoot, exports.ANDROID_RES_PATH, 'raw');
168    const inputFilename = path_1.basename(soundFileRelativePath);
169    if (inputFilename) {
170        try {
171            const sourceFilepath = path_1.resolve(projectRoot, soundFileRelativePath);
172            const destinationFilepath = path_1.resolve(rawResourcesPath, inputFilename);
173            if (!fs_1.existsSync(rawResourcesPath)) {
174                fs_1.mkdirSync(rawResourcesPath, { recursive: true });
175            }
176            fs_1.copyFileSync(sourceFilepath, destinationFilepath);
177        }
178        catch (e) {
179            throw new Error(ERROR_MSG_PREFIX + 'Encountered an issue copying Android notification sounds: ' + e);
180        }
181    }
182}
183exports.withNotificationsAndroid = (config, { icon = null, color = null, sounds = [] }) => {
184    config = exports.withNotificationIconColor(config, { color });
185    config = exports.withNotificationIcons(config, { icon });
186    config = exports.withNotificationManifest(config, { icon, color });
187    config = exports.withNotificationSounds(config, { sounds });
188    return config;
189};
190