@ammarahmed/notifee-react-native
Version:
Notifee - a feature rich notifications library for React Native.
705 lines (591 loc) • 19.3 kB
text/typescript
/* eslint-disable @typescript-eslint/ban-ts-comment */
/*
* Copyright (c) 2016-present Invertase Limited
*/
import { Image } from 'react-native';
import {
objectHasProperty,
isArray,
isArrayOfStrings,
isBoolean,
isNumber,
isObject,
isString,
isUndefined,
isIOS,
} from '../utils';
import { AndroidImportance } from '../types/NotificationAndroid';
import {
AndroidBadgeIconType,
AndroidCategory,
AndroidDefaults,
AndroidFlags,
AndroidGroupAlertBehavior,
AndroidProgress,
AndroidStyle,
AndroidVisibility,
NotificationAndroid,
} from '../types/NotificationAndroid';
import {
isValidColor,
isValidLightPattern,
isValidTimestamp,
isValidVibratePattern,
} from './validate';
import {
validateAndroidBigPictureStyle,
validateAndroidBigTextStyle,
validateAndroidInboxStyle,
validateAndroidMessagingStyle,
} from './validateAndroidStyle';
import validateAndroidPressAction from './validateAndroidPressAction';
import validateAndroidFullScreenAction from './validateAndroidFullScreenAction';
import validateAndroidAction from './validateAndroidAction';
export default function validateAndroidNotification(
android?: NotificationAndroid,
): NotificationAndroid {
// Notification default values
const out: NotificationAndroid = {
autoCancel: true,
asForegroundService: false,
lightUpScreen: false,
badgeIconType: AndroidBadgeIconType.LARGE,
colorized: false,
chronometerDirection: 'up',
defaults: [AndroidDefaults.ALL],
groupAlertBehavior: AndroidGroupAlertBehavior.ALL,
groupSummary: false,
localOnly: false,
ongoing: false,
loopSound: false,
onlyAlertOnce: false,
importance: AndroidImportance.DEFAULT,
showTimestamp: false,
smallIcon: 'ic_launcher',
showChronometer: false,
visibility: AndroidVisibility.PRIVATE,
circularLargeIcon: false,
};
/* Skip validating if iOS in release */
if (isIOS && !__DEV__) return out;
if (isUndefined(android)) {
return out;
}
if (!isUndefined(android) && !isObject(android)) {
throw new Error("'notification.android' expected an object value.");
}
/**
* actions
*/
if (objectHasProperty(android, 'actions') && android.actions !== undefined) {
if (!isArray(android.actions)) {
throw new Error("'notification.android.actions' expected an array of AndroidAction types.");
}
const actions = [];
try {
for (let i = 0; i < android.actions.length; i++) {
actions.push(validateAndroidAction(android.actions[i]));
}
} catch (e: any) {
throw new Error(`'notification.android.actions' invalid AndroidAction. ${e.message}.`);
}
if (actions.length) {
out.actions = actions;
}
}
/**
* asForegroundService
*/
if (objectHasProperty(android, 'asForegroundService')) {
if (!isBoolean(android.asForegroundService)) {
throw new Error("'notification.android.asForegroundService' expected a boolean value.");
}
out.asForegroundService = android.asForegroundService;
}
/**
* lightUpScreen
*/
if (objectHasProperty(android, 'lightUpScreen')) {
if (!isBoolean(android.lightUpScreen)) {
throw new Error("'notification.android.lightUpScreen' expected a boolean value.");
}
out.lightUpScreen = android.lightUpScreen;
}
/**
* autoCancel
*/
if (objectHasProperty(android, 'autoCancel')) {
if (!isBoolean(android.autoCancel)) {
throw new Error("'notification.android.autoCancel' expected a boolean value.");
}
out.autoCancel = android.autoCancel;
}
/**
* badgeCount
*/
if (objectHasProperty(android, 'badgeCount')) {
if (!isNumber(android.badgeCount)) {
throw new Error("'notification.android.badgeCount' expected a number value.");
}
out.badgeCount = android.badgeCount;
}
/**
* badgeIconType
*/
if (objectHasProperty(android, 'badgeIconType') && !isUndefined(android.badgeIconType)) {
if (!Object.values(AndroidBadgeIconType).includes(android.badgeIconType)) {
throw new Error(
"'notification.android.badgeIconType' expected a valid AndroidBadgeIconType.",
);
}
out.badgeIconType = android.badgeIconType;
}
/**
* category
*/
if (objectHasProperty(android, 'category') && !isUndefined(android.category)) {
if (!Object.values(AndroidCategory).includes(android.category)) {
throw new Error("'notification.android.category' expected a valid AndroidCategory.");
}
out.category = android.category;
}
/**
* channelId
*/
if (!isString(android.channelId)) {
throw new Error("'notification.android.channelId' expected a string value.");
}
out.channelId = android.channelId;
/**
* color
*/
if (objectHasProperty(android, 'color') && !isUndefined(android.color)) {
if (!isString(android.color)) {
throw new Error("'notification.android.color' expected a string value.");
}
if (!isValidColor(android.color)) {
throw new Error(
"'notification.android.color' invalid color. Expected an AndroidColor or hexadecimal string value.",
);
}
out.color = android.color;
}
/**
* colorized
*/
if (objectHasProperty(android, 'colorized')) {
if (!isBoolean(android.colorized)) {
throw new Error("'notification.android.colorized' expected a boolean value.");
}
out.colorized = android.colorized;
}
/**
* chronometerDirection
*/
if (objectHasProperty(android, 'chronometerDirection')) {
if (!isString(android.chronometerDirection)) {
throw new Error("'notification.android.chronometerDirection' expected a string value.");
}
if (android.chronometerDirection !== 'up' && android.chronometerDirection !== 'down') {
throw new Error(`'notification.android.chronometerDirection' must be one of "up" or "down".`);
}
out.chronometerDirection = android.chronometerDirection;
}
/**
* defaults
*/
if (objectHasProperty(android, 'defaults') && !isUndefined(android.defaults)) {
if (!isArray(android.defaults)) {
throw new Error("'notification.android.defaults' expected an array.");
}
if (android.defaults.length === 0) {
throw new Error(
"'notification.android.defaults' expected an array containing AndroidDefaults.",
);
}
const defaults = Object.values(AndroidDefaults);
for (let i = 0; i < android.defaults.length; i++) {
if (!defaults.includes(android.defaults[i])) {
throw new Error(
"'notification.android.defaults' invalid array value, expected an AndroidDefaults value.",
);
}
}
out.defaults = android.defaults;
}
/**
* groupId
*/
if (objectHasProperty(android, 'groupId')) {
if (!isString(android.groupId)) {
throw new Error("'notification.android.groupId' expected a string value.");
}
out.groupId = android.groupId;
}
/**
* groupAlertBehavior
*/
if (
objectHasProperty(android, 'groupAlertBehavior') &&
!isUndefined(android.groupAlertBehavior)
) {
if (!Object.values(AndroidGroupAlertBehavior).includes(android.groupAlertBehavior)) {
throw new Error(
"'notification.android.groupAlertBehavior' expected a valid AndroidGroupAlertBehavior.",
);
}
out.groupAlertBehavior = android.groupAlertBehavior;
}
/**
* groupSummary
*/
if (objectHasProperty(android, 'groupSummary')) {
if (!isBoolean(android.groupSummary)) {
throw new Error("'notification.android.groupSummary' expected a boolean value.");
}
out.groupSummary = android.groupSummary;
}
if (objectHasProperty(android, 'inputHistory')) {
if (!isArrayOfStrings(android.inputHistory)) {
throw new Error("'notification.android.inputHistory' expected an array of string values.");
}
out.inputHistory = android.inputHistory;
}
/**
* largeIcon
*/
if (objectHasProperty(android, 'largeIcon')) {
if (
(!isNumber(android.largeIcon) &&
!isString(android.largeIcon) &&
!isObject(android.largeIcon)) ||
(isString(android.largeIcon) && !android.largeIcon.length)
) {
throw new Error(
"'notification.android.largeIcon' expected a React Native ImageResource value or a valid string URL.",
);
}
if (isNumber(android.largeIcon) || isObject(android.largeIcon)) {
const image = Image.resolveAssetSource(android.largeIcon);
out.largeIcon = image.uri;
} else {
out.largeIcon = android.largeIcon;
}
if (isBoolean(android.circularLargeIcon)) {
out.circularLargeIcon = android.circularLargeIcon;
}
}
/**
* lights
*/
if (objectHasProperty(android, 'lights') && !isUndefined(android.lights)) {
if (!isArray(android.lights)) {
throw new Error(
"'notification.android.lights' expected an array value containing the color, on ms and off ms.",
);
}
const [valid, property] = isValidLightPattern(android.lights);
if (!valid) {
switch (property) {
case 'color':
throw new Error(
"'notification.android.lights' invalid color. Expected an AndroidColor or hexadecimal string value.",
);
case 'onMs':
throw new Error(
`'notification.android.lights' invalid "on" millisecond value, expected a number greater than 0.`,
);
case 'offMs':
throw new Error(
`'notification.android.lights' invalid "off" millisecond value, expected a number greater than 0.`,
);
}
}
out.lights = android.lights;
}
/**
* localOnly
*/
if (objectHasProperty(android, 'localOnly')) {
if (!isBoolean(android.localOnly)) {
throw new Error("'notification.android.localOnly' expected a boolean value.");
}
out.localOnly = android.localOnly;
}
/**
* ongoing
*/
if (objectHasProperty(android, 'ongoing')) {
if (!isBoolean(android.ongoing)) {
throw new Error("'notification.android.ongoing' expected a boolean value.");
}
out.ongoing = android.ongoing;
}
/**
* loopSound
*/
if (objectHasProperty(android, 'loopSound')) {
if (!isBoolean(android.loopSound)) {
throw new Error("'notification.android.loopSound' expected a boolean value.");
}
out.loopSound = android.loopSound;
}
/**
* flags
*/
if (objectHasProperty(android, 'flags') && !isUndefined(android.flags)) {
if (!isArray(android.flags)) {
throw new Error("'notification.android.flags' expected an array.");
}
if (android.flags.length === 0) {
throw new Error("'notification.android.flags' expected an array containing AndroidDefaults.");
}
const defaults = Object.values(AndroidFlags);
for (let i = 0; i < android.flags.length; i++) {
if (!defaults.includes(android.flags[i])) {
throw new Error(
"'notification.android.flags' invalid array value, expected an AndroidFlags value.",
);
}
}
out.flags = android.flags;
}
/**
* onlyAlertOnce
*/
if (objectHasProperty(android, 'onlyAlertOnce')) {
if (!isBoolean(android.onlyAlertOnce)) {
throw new Error("'notification.android.onlyAlertOnce' expected a boolean value.");
}
out.onlyAlertOnce = android.onlyAlertOnce;
}
/**
* pressAction
*/
if (objectHasProperty(android, 'pressAction') && !isUndefined(android.pressAction)) {
try {
out.pressAction = validateAndroidPressAction(android.pressAction);
} catch (e: any) {
throw new Error(`'notification.android.pressAction' ${e.message}`);
}
}
/**
* fullScreenAction
*/
if (objectHasProperty(android, 'fullScreenAction') && !isUndefined(android.fullScreenAction)) {
try {
out.fullScreenAction = validateAndroidFullScreenAction(android.fullScreenAction);
} catch (e: any) {
throw new Error(`'notification.android.fullScreenAction' ${e.message}`);
}
}
/**
* importance
*/
if (objectHasProperty(android, 'importance') && !isUndefined(android.importance)) {
if (!Object.values(AndroidImportance).includes(android.importance)) {
throw new Error("'notification.android.importance' expected a valid Importance.");
}
out.importance = android.importance;
}
/**
* progress
*/
if (objectHasProperty(android, 'progress') && !isUndefined(android.progress)) {
if (!isObject(android.progress)) {
throw new Error("'notification.android.progress' expected an object value.");
}
const progress: AndroidProgress = {
indeterminate: false,
};
if (objectHasProperty(android.progress, 'indeterminate')) {
if (!isBoolean(android.progress.indeterminate)) {
throw new Error("'notification.android.progress.indeterminate' expected a boolean value.");
}
progress.indeterminate = android.progress.indeterminate;
}
if (!isUndefined(android.progress.max)) {
if (!isNumber(android.progress.max) || android.progress.max < 0) {
throw new Error("'notification.android.progress.max' expected a positive number value.");
}
if (isUndefined(android.progress.current)) {
throw new Error(
"'notification.android.progress.max' when providing a max value, you must also specify a current value.",
);
}
progress.max = android.progress.max;
}
if (!isUndefined(android.progress.current)) {
if (!isNumber(android.progress.current) || android.progress.current < 0) {
throw new Error(
"'notification.android.progress.current' expected a positive number value.",
);
}
if (isUndefined(android.progress.max)) {
throw new Error(
"'notification.android.progress.current' when providing a current value, you must also specify a `max` value.",
);
}
progress.current = android.progress.current;
}
// We have a max/current value
if (!isUndefined(progress.max) && !isUndefined(progress.current)) {
if (progress.current > progress.max) {
throw new Error(
"'notification.android.progress' the current value cannot be greater than the max value.",
);
}
}
out.progress = progress;
}
/**
* showTimestamp
*/
if (objectHasProperty(android, 'showTimestamp')) {
if (!isBoolean(android.showTimestamp)) {
throw new Error("'notification.android.showTimestamp' expected a boolean value.");
}
out.showTimestamp = android.showTimestamp;
}
/**
* smallIcon
*/
if (objectHasProperty(android, 'smallIcon') && !isUndefined(android.smallIcon)) {
if (!isString(android.smallIcon)) {
throw new Error("'notification.android.smallIcon' expected value to be a string.");
}
out.smallIcon = android.smallIcon;
}
/**
* smallIconLevel
*/
if (objectHasProperty(android, 'smallIconLevel') && !isUndefined(android.smallIcon)) {
if (!isNumber(android.smallIconLevel)) {
throw new Error("'notification.android.smallIconLevel' expected value to be a number.");
}
out.smallIconLevel = android.smallIconLevel;
}
/**
* sortKey
*/
if (objectHasProperty(android, 'sortKey')) {
if (!isString(android.sortKey)) {
throw new Error("'notification.android.sortKey' expected a string value.");
}
out.sortKey = android.sortKey;
}
/**
* style
*/
if (objectHasProperty(android, 'style') && !isUndefined(android.style)) {
if (!isObject(android.style)) {
throw new Error("'notification.android.style' expected an object value.");
}
switch (android.style.type) {
case AndroidStyle.BIGPICTURE:
out.style = validateAndroidBigPictureStyle(android.style);
break;
case AndroidStyle.BIGTEXT:
out.style = validateAndroidBigTextStyle(android.style);
break;
case AndroidStyle.INBOX:
out.style = validateAndroidInboxStyle(android.style);
break;
case AndroidStyle.MESSAGING:
out.style = validateAndroidMessagingStyle(android.style);
break;
default:
throw new Error(
"'notification.android.style' style type must be one of AndroidStyle.BIGPICTURE, AndroidStyle.BIGTEXT, AndroidStyle.INBOX or AndroidStyle.MESSAGING.",
);
}
}
/**
* tag
*/
if (objectHasProperty(android, 'tag') && android.tag !== undefined) {
if (!isString(android.tag)) {
throw new Error("'notification.android.tag' expected a string value.");
}
if (android.tag.includes('|')) {
throw new Error(`'notification.android.tag' tag cannot contain the "|" (pipe) character.`);
}
out.tag = android.tag;
}
/**
* ticker
*/
if (objectHasProperty(android, 'ticker')) {
if (!isString(android.ticker)) {
throw new Error("'notification.android.ticker' expected a string value.");
}
out.ticker = android.ticker;
}
/**
* timeoutAfter
*/
if (objectHasProperty(android, 'timeoutAfter') && android.timeoutAfter !== undefined) {
if (!isNumber(android.timeoutAfter)) {
throw new Error("'notification.android.timeoutAfter' expected a number value.");
}
if (!isValidTimestamp(android.timeoutAfter)) {
throw new Error("'notification.android.timeoutAfter' invalid millisecond timestamp.");
}
out.timeoutAfter = android.timeoutAfter;
}
/**
* showChronometer
*/
if (objectHasProperty(android, 'showChronometer')) {
if (!isBoolean(android.showChronometer)) {
throw new Error("'notification.android.showChronometer' expected a boolean value.");
}
out.showChronometer = android.showChronometer;
}
/**
* vibrationPattern
*/
if (objectHasProperty(android, 'vibrationPattern') && android.vibrationPattern !== undefined) {
if (!isArray(android.vibrationPattern) || !isValidVibratePattern(android.vibrationPattern)) {
throw new Error(
"'notification.android.vibrationPattern' expected an array containing an even number of positive values.",
);
}
out.vibrationPattern = android.vibrationPattern;
}
/**
* visibility
*/
if (objectHasProperty(android, 'visibility') && android.visibility !== undefined) {
if (!Object.values(AndroidVisibility).includes(android.visibility)) {
throw new Error(
"'notification.android.visibility' expected a valid AndroidVisibility value.",
);
}
out.visibility = android.visibility;
}
/**
* timestamp
*/
if (objectHasProperty(android, 'timestamp') && android.timestamp !== undefined) {
if (!isNumber(android.timestamp)) {
throw new Error("'notification.android.timestamp' expected a number value.");
}
if (!isValidTimestamp(android.timestamp)) {
throw new Error(
"'notification.android.timestamp' invalid millisecond timestamp, date must be a positive number",
);
}
out.timestamp = android.timestamp;
}
/**
* sound
*/
if (objectHasProperty(android, 'sound') && android.sound !== undefined) {
if (!isString(android.sound)) {
throw new Error("'notification.sound' expected a valid sound string.");
}
out.sound = android.sound;
}
return out;
}