react-native-bootsplash 4.7.5 → 5.0.0-beta.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +214 -107
- package/RNBootSplash.podspec +1 -2
- package/android/.npmignore +11 -0
- package/android/build.gradle +0 -1
- package/android/src/main/java/com/zoontek/rnbootsplash/RNBootSplash.java +3 -2
- package/android/src/main/java/com/zoontek/rnbootsplash/RNBootSplashDialog.java +49 -0
- package/android/src/main/java/com/zoontek/rnbootsplash/RNBootSplashModuleImpl.java +157 -87
- package/android/src/main/res/anim/bootsplash_fade_in.xml +7 -0
- package/android/src/main/res/anim/bootsplash_fade_out.xml +7 -0
- package/android/src/main/res/drawable/compat_splash_screen.xml +19 -0
- package/android/src/main/res/values/attrs.xml +8 -0
- package/android/src/main/res/values/public.xml +7 -0
- package/android/src/main/res/values/styles.xml +29 -0
- package/android/src/main/res/values-v31/styles.xml +7 -0
- package/android/src/newarch/com/zoontek/rnbootsplash/RNBootSplashModule.java +11 -4
- package/android/src/oldarch/com/zoontek/rnbootsplash/RNBootSplashModule.java +13 -4
- package/dist/commonjs/NativeRNBootSplash.js.map +1 -1
- package/dist/commonjs/addon/index.js +3 -0
- package/dist/commonjs/addon/index.js.map +1 -0
- package/dist/commonjs/generate.js +289 -194
- package/dist/commonjs/generate.js.map +1 -1
- package/dist/commonjs/index.js +115 -7
- package/dist/commonjs/index.js.map +1 -1
- package/dist/module/NativeRNBootSplash.js.map +1 -1
- package/dist/module/addon/index.js +3 -0
- package/dist/module/addon/index.js.map +1 -0
- package/dist/module/generate.js +287 -195
- package/dist/module/generate.js.map +1 -1
- package/dist/module/index.js +113 -6
- package/dist/module/index.js.map +1 -1
- package/dist/typescript/NativeRNBootSplash.d.ts +6 -3
- package/dist/typescript/NativeRNBootSplash.d.ts.map +1 -1
- package/dist/typescript/addon/index.d.ts +3 -0
- package/dist/typescript/addon/index.d.ts.map +1 -0
- package/dist/typescript/generate.d.ts +47 -14
- package/dist/typescript/generate.d.ts.map +1 -1
- package/dist/typescript/index.d.ts +33 -5
- package/dist/typescript/index.d.ts.map +1 -1
- package/example/android/app/debug.keystore +0 -0
- package/example/vendor/bundle/ruby/2.7.0/gems/ffi-1.15.5/ext/ffi_c/libffi/.travis/compile +351 -0
- package/example/vendor/bundle/ruby/2.7.0/gems/ffi-1.15.5/ext/ffi_c/libffi/testsuite/libffi.bhaible/Makefile +28 -0
- package/ios/.DS_Store +0 -0
- package/ios/.npmignore +8 -0
- package/ios/RNBootSplash.mm +101 -95
- package/package.json +20 -13
- package/react-native.config.js +74 -76
- package/src/.DS_Store +0 -0
- package/src/.npmignore +1 -0
- package/src/NativeRNBootSplash.ts +3 -4
- package/src/addon/index.ts +788 -0
- package/src/generate.ts +457 -232
- package/src/index.ts +205 -8
- package/RNBootSplash.res +0 -29
- package/bsconfig.json +0 -14
package/src/generate.ts
CHANGED
|
@@ -1,57 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AndroidProjectConfig,
|
|
3
|
+
CommandFunction,
|
|
4
|
+
IOSProjectConfig,
|
|
5
|
+
} from "@react-native-community/cli-types";
|
|
1
6
|
import fs from "fs-extra";
|
|
2
7
|
import path from "path";
|
|
3
8
|
import pc from "picocolors";
|
|
9
|
+
import type { Sharp } from "sharp";
|
|
4
10
|
import sharp from "sharp";
|
|
11
|
+
import type { Manifest } from ".";
|
|
12
|
+
|
|
13
|
+
export type Color = {
|
|
14
|
+
hex: string;
|
|
15
|
+
rgb: {
|
|
16
|
+
R: string;
|
|
17
|
+
G: string;
|
|
18
|
+
B: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const androidColorRegex =
|
|
23
|
+
/<color name="bootsplash_background">#\w+<\/color>/g;
|
|
24
|
+
|
|
25
|
+
const workingPath = process.env.INIT_CWD ?? process.env.PWD ?? process.cwd();
|
|
26
|
+
|
|
27
|
+
const parseColor = (value: string): Color => {
|
|
28
|
+
const up = value.toUpperCase().replace(/[^0-9A-F]/g, "");
|
|
29
|
+
const hex = "#" + (up.length === 3 ? up + up : up);
|
|
30
|
+
|
|
31
|
+
if (hex.length !== 7) {
|
|
32
|
+
log.error("--background-color value is not a valid hexadecimal color.");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const rgb: Color["rgb"] = {
|
|
37
|
+
R: (parseInt("" + hex[1] + hex[2], 16) / 255).toPrecision(15),
|
|
38
|
+
G: (parseInt("" + hex[3] + hex[4], 16) / 255).toPrecision(15),
|
|
39
|
+
B: (parseInt("" + hex[5] + hex[6], 16) / 255).toPrecision(15),
|
|
40
|
+
};
|
|
5
41
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const androidColorName = "bootsplash_background";
|
|
9
|
-
const androidColorRegex = /<color name="bootsplash_background">#\w+<\/color>/g;
|
|
42
|
+
return { hex, rgb };
|
|
43
|
+
};
|
|
10
44
|
|
|
11
45
|
const ContentsJson = `{
|
|
12
46
|
"images": [
|
|
13
47
|
{
|
|
14
48
|
"idiom": "universal",
|
|
15
|
-
"filename": "
|
|
49
|
+
"filename": "bootsplash_logo.png",
|
|
16
50
|
"scale": "1x"
|
|
17
51
|
},
|
|
18
52
|
{
|
|
19
53
|
"idiom": "universal",
|
|
20
|
-
"filename": "
|
|
54
|
+
"filename": "bootsplash_logo@2x.png",
|
|
21
55
|
"scale": "2x"
|
|
22
56
|
},
|
|
23
57
|
{
|
|
24
58
|
"idiom": "universal",
|
|
25
|
-
"filename": "
|
|
59
|
+
"filename": "bootsplash_logo@3x.png",
|
|
26
60
|
"scale": "3x"
|
|
27
61
|
}
|
|
28
62
|
],
|
|
29
63
|
"info": {
|
|
30
|
-
"
|
|
31
|
-
"
|
|
64
|
+
"author": "xcode",
|
|
65
|
+
"version": 1
|
|
32
66
|
}
|
|
33
67
|
}
|
|
34
68
|
`;
|
|
35
69
|
|
|
36
70
|
const getStoryboard = ({
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
71
|
+
logoHeight,
|
|
72
|
+
logoWidth,
|
|
73
|
+
background: { R, G, B },
|
|
40
74
|
}: {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
75
|
+
logoHeight: number;
|
|
76
|
+
logoWidth: number;
|
|
77
|
+
background: Color["rgb"];
|
|
44
78
|
}) => {
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
const
|
|
79
|
+
const frameWidth = 375;
|
|
80
|
+
const frameHeight = 667;
|
|
81
|
+
const logoX = (frameWidth - logoWidth) / 2;
|
|
82
|
+
const logoY = (frameHeight - logoHeight) / 2;
|
|
48
83
|
|
|
49
84
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
50
|
-
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="
|
|
85
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
|
51
86
|
<device id="retina4_7" orientation="portrait" appearance="light"/>
|
|
52
87
|
<dependencies>
|
|
53
88
|
<deployment identifier="iOS"/>
|
|
54
|
-
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="
|
|
89
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21678"/>
|
|
55
90
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
56
91
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
57
92
|
</dependencies>
|
|
@@ -60,24 +95,19 @@ const getStoryboard = ({
|
|
|
60
95
|
<scene sceneID="EHf-IW-A2E">
|
|
61
96
|
<objects>
|
|
62
97
|
<viewController modalTransitionStyle="crossDissolve" id="01J-lp-oVM" sceneMemberID="viewController">
|
|
63
|
-
<view key="view" autoresizesSubviews="NO"
|
|
64
|
-
<rect key="frame" x="0.0" y="0.0" width="
|
|
65
|
-
<autoresizingMask key="autoresizingMask"/>
|
|
98
|
+
<view key="view" autoresizesSubviews="NO" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
|
99
|
+
<rect key="frame" x="0.0" y="0.0" width="${frameWidth}" height="${frameHeight}"/>
|
|
100
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
66
101
|
<subviews>
|
|
67
102
|
<imageView autoresizesSubviews="NO" clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" image="BootSplashLogo" translatesAutoresizingMaskIntoConstraints="NO" id="3lX-Ut-9ad">
|
|
68
|
-
<rect key="frame" x="${
|
|
69
|
-
(667 - height) / 2
|
|
70
|
-
}" width="${width}" height="${height}"/>
|
|
103
|
+
<rect key="frame" x="${logoX}" y="${logoY}" width="${logoWidth}" height="${logoHeight}"/>
|
|
71
104
|
<accessibility key="accessibilityConfiguration">
|
|
72
105
|
<accessibilityTraits key="traits" image="YES" notEnabled="YES"/>
|
|
73
106
|
</accessibility>
|
|
74
107
|
</imageView>
|
|
75
108
|
</subviews>
|
|
76
109
|
<viewLayoutGuide key="safeArea" id="Bcu-3y-fUS"/>
|
|
77
|
-
<color key="backgroundColor" red="${
|
|
78
|
-
<accessibility key="accessibilityConfiguration">
|
|
79
|
-
<accessibilityTraits key="traits" notEnabled="YES"/>
|
|
80
|
-
</accessibility>
|
|
110
|
+
<color key="backgroundColor" red="${R}" green="${G}" blue="${B}" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
|
|
81
111
|
<constraints>
|
|
82
112
|
<constraint firstItem="3lX-Ut-9ad" firstAttribute="centerX" secondItem="Ze5-6b-2t3" secondAttribute="centerX" id="Fh9-Fy-1nT"/>
|
|
83
113
|
<constraint firstItem="3lX-Ut-9ad" firstAttribute="centerY" secondItem="Ze5-6b-2t3" secondAttribute="centerY" id="nvB-Ic-PnI"/>
|
|
@@ -90,164 +120,284 @@ const getStoryboard = ({
|
|
|
90
120
|
</scene>
|
|
91
121
|
</scenes>
|
|
92
122
|
<resources>
|
|
93
|
-
<image name="
|
|
123
|
+
<image name="BootSplashLogo" width="${logoWidth}" height="${logoHeight}"/>
|
|
94
124
|
</resources>
|
|
95
125
|
</document>
|
|
96
126
|
`;
|
|
97
127
|
};
|
|
98
128
|
|
|
99
|
-
const log = {
|
|
100
|
-
error: (text: string) => console.log(pc.red(text)),
|
|
129
|
+
export const log = {
|
|
130
|
+
error: (text: string) => console.log(pc.red(`❌ ${text}`)),
|
|
101
131
|
text: (text: string) => console.log(text),
|
|
102
|
-
|
|
132
|
+
title: (emoji: string, text: string) =>
|
|
133
|
+
console.log(`\n${emoji} ${pc.underline(pc.bold(text))}`),
|
|
134
|
+
warn: (text: string) => console.log(pc.yellow(`⚠️ ${text}`)),
|
|
103
135
|
};
|
|
104
136
|
|
|
105
|
-
const
|
|
106
|
-
|
|
137
|
+
export const logWrite = (
|
|
138
|
+
filePath: string,
|
|
139
|
+
dimensions?: { width: number; height: number },
|
|
140
|
+
) =>
|
|
141
|
+
console.log(
|
|
142
|
+
` ${path.relative(workingPath, filePath)}` +
|
|
143
|
+
(dimensions != null ? ` (${dimensions.width}x${dimensions.height})` : ""),
|
|
144
|
+
);
|
|
107
145
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
146
|
+
const ensureSupportedFormat = async (
|
|
147
|
+
name: string,
|
|
148
|
+
image: Sharp | undefined,
|
|
149
|
+
) => {
|
|
150
|
+
if (image == null) {
|
|
151
|
+
return;
|
|
113
152
|
}
|
|
114
153
|
|
|
115
|
-
|
|
116
|
-
|
|
154
|
+
const { format } = await image.metadata();
|
|
155
|
+
|
|
156
|
+
if (format !== "png" && format !== "svg") {
|
|
157
|
+
log.error(`${name} image file format (${format}) is not supported`);
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
117
160
|
};
|
|
118
161
|
|
|
119
|
-
|
|
120
|
-
android,
|
|
121
|
-
|
|
162
|
+
const getAndroidResPath = (
|
|
163
|
+
android: AndroidProjectConfig,
|
|
164
|
+
{
|
|
165
|
+
brandHeight,
|
|
166
|
+
brandWidth,
|
|
167
|
+
flavor,
|
|
168
|
+
logoHeight,
|
|
169
|
+
logoWidth,
|
|
170
|
+
}: {
|
|
171
|
+
brandHeight: number;
|
|
172
|
+
brandWidth: number;
|
|
173
|
+
flavor: string;
|
|
174
|
+
logoHeight: number;
|
|
175
|
+
logoWidth: number;
|
|
176
|
+
},
|
|
177
|
+
): string | undefined => {
|
|
178
|
+
const androidResPath = path.resolve(
|
|
179
|
+
android.sourceDir,
|
|
180
|
+
android.appName,
|
|
181
|
+
"src",
|
|
182
|
+
flavor,
|
|
183
|
+
"res",
|
|
184
|
+
);
|
|
122
185
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
186
|
+
if (!fs.existsSync(androidResPath)) {
|
|
187
|
+
log.warn(
|
|
188
|
+
`No ${path.relative(
|
|
189
|
+
workingPath,
|
|
190
|
+
androidResPath,
|
|
191
|
+
)} directory found. Skipping Android assets generation…`,
|
|
192
|
+
);
|
|
193
|
+
} else if (logoWidth > 288 || logoHeight > 288) {
|
|
194
|
+
log.warn(
|
|
195
|
+
"Logo size exceeding 288x288dp will be cropped by Android. Skipping Android assets generation…",
|
|
196
|
+
);
|
|
197
|
+
} else if (brandHeight > 80 || brandWidth > 200) {
|
|
198
|
+
log.warn(
|
|
199
|
+
"Brand size exceeding 200x80dp will be cropped by Android. Skipping Android assets generation…",
|
|
200
|
+
);
|
|
201
|
+
} else {
|
|
202
|
+
if (logoWidth > 192 || logoHeight > 192) {
|
|
203
|
+
log.warn(`Logo size exceeds 192x192dp. It might be cropped by Android.`);
|
|
204
|
+
}
|
|
126
205
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
platforms,
|
|
131
|
-
}: {
|
|
132
|
-
android: {
|
|
133
|
-
sourceDir: string;
|
|
134
|
-
appName: string;
|
|
135
|
-
} | null;
|
|
136
|
-
ios: {
|
|
137
|
-
projectPath: string;
|
|
138
|
-
} | null;
|
|
139
|
-
|
|
140
|
-
workingPath: string;
|
|
141
|
-
logoPath: string;
|
|
142
|
-
assetsPath?: string;
|
|
143
|
-
|
|
144
|
-
backgroundColor: string;
|
|
145
|
-
flavor: string;
|
|
146
|
-
logoWidth: number;
|
|
147
|
-
platforms: string[];
|
|
148
|
-
}) => {
|
|
149
|
-
const platformsIncludesAndroid = platforms.includes("android");
|
|
150
|
-
const platformsIncludesIOS = platforms.includes("ios");
|
|
206
|
+
return androidResPath;
|
|
207
|
+
}
|
|
208
|
+
};
|
|
151
209
|
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
process.exit(1);
|
|
210
|
+
const getIOSProjectPath = (ios: IOSProjectConfig): string | undefined => {
|
|
211
|
+
if (ios.xcodeProject == null) {
|
|
212
|
+
log.warn("No Xcode project found. Skipping iOS assets generation…");
|
|
213
|
+
return;
|
|
157
214
|
}
|
|
158
215
|
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
216
|
+
const iosProjectPath = path
|
|
217
|
+
.resolve(ios.sourceDir, ios.xcodeProject.name)
|
|
218
|
+
.replace(/\.(xcodeproj|xcworkspace)$/, "");
|
|
162
219
|
|
|
163
|
-
if (
|
|
164
|
-
log.
|
|
165
|
-
|
|
220
|
+
if (!fs.existsSync(iosProjectPath)) {
|
|
221
|
+
log.warn(
|
|
222
|
+
`No ${path.relative(
|
|
223
|
+
workingPath,
|
|
224
|
+
iosProjectPath,
|
|
225
|
+
)} directory found. Skipping iOS assets generation…`,
|
|
226
|
+
);
|
|
227
|
+
} else {
|
|
228
|
+
return iosProjectPath;
|
|
166
229
|
}
|
|
230
|
+
};
|
|
167
231
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
.resize(logoWidth)
|
|
171
|
-
.toBuffer()
|
|
172
|
-
.then((buffer) => sharp(buffer).metadata())
|
|
173
|
-
.then(({ height = 0 }) => height);
|
|
174
|
-
|
|
175
|
-
const shouldSkipAndroid = logoWidth > 288 || logoHeight > 288;
|
|
232
|
+
export type AddonConfig = {
|
|
233
|
+
licenseKey: string;
|
|
176
234
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
};
|
|
235
|
+
androidResPath: string | undefined;
|
|
236
|
+
iosProjectPath: string | undefined;
|
|
237
|
+
assetsOutputPath: string | undefined;
|
|
181
238
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
239
|
+
logoHeight: number;
|
|
240
|
+
logoWidth: number;
|
|
241
|
+
brandHeight: number;
|
|
242
|
+
brandWidth: number;
|
|
186
243
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
} else if (logoHeight > 288) {
|
|
190
|
-
logAbove288("height");
|
|
191
|
-
} else if (logoWidth > 192) {
|
|
192
|
-
logAbove192("width");
|
|
193
|
-
} else if (logoHeight > 192) {
|
|
194
|
-
logAbove192("height");
|
|
195
|
-
}
|
|
244
|
+
background: Color;
|
|
245
|
+
brand: Sharp | undefined;
|
|
196
246
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
) =>
|
|
202
|
-
log.text(
|
|
203
|
-
`${emoji} ${path.relative(workingPath, filePath)}` +
|
|
204
|
-
(dimensions != null
|
|
205
|
-
? ` (${dimensions.width}x${dimensions.height})`
|
|
206
|
-
: ""),
|
|
207
|
-
);
|
|
247
|
+
darkBackground: Color | undefined;
|
|
248
|
+
darkLogo: Sharp | undefined;
|
|
249
|
+
darkBrand: Sharp | undefined;
|
|
250
|
+
};
|
|
208
251
|
|
|
209
|
-
|
|
210
|
-
|
|
252
|
+
const requireAddon = ():
|
|
253
|
+
| { execute: (config: AddonConfig) => Promise<void> }
|
|
254
|
+
| undefined => {
|
|
255
|
+
try {
|
|
256
|
+
// eslint-disable-next-line
|
|
257
|
+
return require("./addon");
|
|
258
|
+
} catch {
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
};
|
|
211
262
|
|
|
212
|
-
|
|
263
|
+
export const generate: CommandFunction<{
|
|
264
|
+
logoWidth: number;
|
|
265
|
+
background: string;
|
|
266
|
+
assetsOutput?: string;
|
|
267
|
+
flavor: string;
|
|
268
|
+
platforms: string[];
|
|
213
269
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
270
|
+
licenseKey?: string;
|
|
271
|
+
brand?: string;
|
|
272
|
+
brandWidth: number;
|
|
273
|
+
darkBackground?: string;
|
|
274
|
+
darkLogo?: string;
|
|
275
|
+
darkBrand?: string;
|
|
276
|
+
}> = async (
|
|
277
|
+
[argsLogo],
|
|
278
|
+
{ project: { android, ios } },
|
|
279
|
+
{ flavor, platforms, licenseKey, ...args },
|
|
280
|
+
) => {
|
|
281
|
+
if (argsLogo == null) {
|
|
282
|
+
log.error("Missing required argument 'logo'");
|
|
283
|
+
process.exit(1);
|
|
284
|
+
}
|
|
224
285
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
286
|
+
const assetsOutputPath =
|
|
287
|
+
args.assetsOutput != null
|
|
288
|
+
? path.resolve(workingPath, args.assetsOutput)
|
|
289
|
+
: undefined;
|
|
290
|
+
|
|
291
|
+
const background = parseColor(args.background);
|
|
292
|
+
const logo = sharp(path.resolve(workingPath, argsLogo));
|
|
293
|
+
const logoWidth = args.logoWidth - (args.logoWidth % 2);
|
|
294
|
+
const brandWidth = args.brandWidth - (args.brandWidth % 2);
|
|
295
|
+
|
|
296
|
+
const brand =
|
|
297
|
+
args.brand != null
|
|
298
|
+
? sharp(path.resolve(workingPath, args.brand))
|
|
299
|
+
: undefined;
|
|
300
|
+
|
|
301
|
+
const darkBackground =
|
|
302
|
+
args.darkBackground != null ? parseColor(args.darkBackground) : undefined;
|
|
303
|
+
|
|
304
|
+
const darkLogo =
|
|
305
|
+
args.darkLogo != null
|
|
306
|
+
? sharp(path.resolve(workingPath, args.darkLogo))
|
|
307
|
+
: undefined;
|
|
308
|
+
|
|
309
|
+
const darkBrand =
|
|
310
|
+
args.darkBrand != null
|
|
311
|
+
? sharp(path.resolve(workingPath, args.darkBrand))
|
|
312
|
+
: undefined;
|
|
313
|
+
|
|
314
|
+
const executeAddon =
|
|
315
|
+
brand != null ||
|
|
316
|
+
darkBackground != null ||
|
|
317
|
+
darkLogo != null ||
|
|
318
|
+
darkBrand != null;
|
|
319
|
+
|
|
320
|
+
if (licenseKey != null && !executeAddon) {
|
|
321
|
+
log.warn(
|
|
322
|
+
`You specified a license key but none of the options that requires it.`,
|
|
234
323
|
);
|
|
235
324
|
}
|
|
236
325
|
|
|
237
|
-
if (
|
|
238
|
-
|
|
326
|
+
if (licenseKey == null && executeAddon) {
|
|
327
|
+
const options = [
|
|
328
|
+
brand != null ? "brand" : "",
|
|
329
|
+
darkBackground != null ? "dark-background" : "",
|
|
330
|
+
darkLogo != null ? "dark-logo" : "",
|
|
331
|
+
darkBrand != null ? "dark-brand" : "",
|
|
332
|
+
]
|
|
333
|
+
.filter((option) => option !== "")
|
|
334
|
+
.map((option) => `--${option}`)
|
|
335
|
+
.join(", ");
|
|
336
|
+
|
|
337
|
+
log.error(`You need to specify a license key in order to use ${options}.`);
|
|
338
|
+
process.exit(1);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
if (brand == null && darkBrand != null) {
|
|
342
|
+
log.error("--dark-brand option couldn't be used without --brand.");
|
|
343
|
+
process.exit(1);
|
|
344
|
+
}
|
|
239
345
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
346
|
+
await ensureSupportedFormat("Logo", logo);
|
|
347
|
+
await ensureSupportedFormat("Dark logo", darkLogo);
|
|
348
|
+
await ensureSupportedFormat("Brand", brand);
|
|
349
|
+
await ensureSupportedFormat("Dark brand", darkBrand);
|
|
243
350
|
|
|
244
|
-
|
|
245
|
-
|
|
351
|
+
const logoHeight = await logo
|
|
352
|
+
.clone()
|
|
353
|
+
.resize(logoWidth)
|
|
354
|
+
.toBuffer()
|
|
355
|
+
.then((buffer) => sharp(buffer).metadata())
|
|
356
|
+
.then(({ height = 0 }) => Math.round(height));
|
|
357
|
+
|
|
358
|
+
const brandHeight =
|
|
359
|
+
(await brand
|
|
360
|
+
?.clone()
|
|
361
|
+
.resize(brandWidth)
|
|
362
|
+
.toBuffer()
|
|
363
|
+
.then((buffer) => sharp(buffer).metadata())
|
|
364
|
+
.then(({ height = 0 }) => Math.round(height))) ?? 0;
|
|
365
|
+
|
|
366
|
+
if (logoWidth < args.logoWidth) {
|
|
367
|
+
log.warn(
|
|
368
|
+
`Logo width must be a multiple of 2. It has been rounded to ${logoWidth}dp.`,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
if (brandWidth < args.brandWidth) {
|
|
372
|
+
log.warn(
|
|
373
|
+
`Brand width must be a multiple of 2. It has been rounded to ${brandWidth}dp.`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
246
376
|
|
|
377
|
+
const androidResPath =
|
|
378
|
+
platforms.includes("android") && android != null
|
|
379
|
+
? getAndroidResPath(android, {
|
|
380
|
+
brandHeight,
|
|
381
|
+
brandWidth,
|
|
382
|
+
flavor,
|
|
383
|
+
logoHeight,
|
|
384
|
+
logoWidth,
|
|
385
|
+
})
|
|
386
|
+
: undefined;
|
|
387
|
+
|
|
388
|
+
const iosProjectPath =
|
|
389
|
+
platforms.includes("ios") && ios != null
|
|
390
|
+
? getIOSProjectPath(ios)
|
|
391
|
+
: undefined;
|
|
392
|
+
|
|
393
|
+
if (androidResPath != null) {
|
|
394
|
+
log.title("🤖", "Android");
|
|
395
|
+
|
|
396
|
+
const valuesPath = path.resolve(androidResPath, "values");
|
|
247
397
|
fs.ensureDirSync(valuesPath);
|
|
248
398
|
|
|
249
399
|
const colorsXmlPath = path.resolve(valuesPath, "colors.xml");
|
|
250
|
-
const colorsXmlEntry = `<color name="
|
|
400
|
+
const colorsXmlEntry = `<color name="bootsplash_background">${background.hex}</color>`;
|
|
251
401
|
|
|
252
402
|
if (fs.existsSync(colorsXmlPath)) {
|
|
253
403
|
const colorsXml = fs.readFileSync(colorsXmlPath, "utf-8");
|
|
@@ -268,29 +418,32 @@ export const generate = async ({
|
|
|
268
418
|
"utf-8",
|
|
269
419
|
);
|
|
270
420
|
}
|
|
271
|
-
|
|
272
|
-
logWrite("✏️ ", colorsXmlPath);
|
|
273
421
|
} else {
|
|
274
422
|
fs.writeFileSync(
|
|
275
423
|
colorsXmlPath,
|
|
276
424
|
`<resources>\n ${colorsXmlEntry}\n</resources>\n`,
|
|
277
425
|
"utf-8",
|
|
278
426
|
);
|
|
279
|
-
|
|
280
|
-
logWrite("✨", colorsXmlPath);
|
|
281
427
|
}
|
|
282
428
|
|
|
429
|
+
logWrite(colorsXmlPath);
|
|
430
|
+
|
|
283
431
|
await Promise.all(
|
|
284
432
|
[
|
|
285
|
-
{ ratio: 1,
|
|
286
|
-
{ ratio: 1.5,
|
|
287
|
-
{ ratio: 2,
|
|
288
|
-
{ ratio: 3,
|
|
289
|
-
{ ratio: 4,
|
|
290
|
-
].map(({ ratio,
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
433
|
+
{ ratio: 1, suffix: "mdpi" },
|
|
434
|
+
{ ratio: 1.5, suffix: "hdpi" },
|
|
435
|
+
{ ratio: 2, suffix: "xhdpi" },
|
|
436
|
+
{ ratio: 3, suffix: "xxhdpi" },
|
|
437
|
+
{ ratio: 4, suffix: "xxxhdpi" },
|
|
438
|
+
].map(({ ratio, suffix }) => {
|
|
439
|
+
const drawableDirPath = path.resolve(
|
|
440
|
+
androidResPath,
|
|
441
|
+
`drawable-${suffix}`,
|
|
442
|
+
);
|
|
443
|
+
|
|
444
|
+
fs.ensureDirSync(drawableDirPath);
|
|
445
|
+
|
|
446
|
+
// https://developer.android.com/develop/ui/views/launch/splash-screen#dimensions
|
|
294
447
|
const canvasSize = 288 * ratio;
|
|
295
448
|
|
|
296
449
|
// https://sharp.pixelplumbing.com/api-constructor
|
|
@@ -308,7 +461,9 @@ export const generate = async ({
|
|
|
308
461
|
},
|
|
309
462
|
});
|
|
310
463
|
|
|
311
|
-
|
|
464
|
+
const filePath = path.resolve(drawableDirPath, "bootsplash_logo.png");
|
|
465
|
+
|
|
466
|
+
return logo
|
|
312
467
|
.clone()
|
|
313
468
|
.resize(logoWidth * ratio)
|
|
314
469
|
.toBuffer()
|
|
@@ -319,86 +474,156 @@ export const generate = async ({
|
|
|
319
474
|
.toFile(filePath),
|
|
320
475
|
)
|
|
321
476
|
.then(() => {
|
|
322
|
-
logWrite(
|
|
477
|
+
logWrite(filePath, {
|
|
478
|
+
width: canvasSize,
|
|
479
|
+
height: canvasSize,
|
|
480
|
+
});
|
|
323
481
|
});
|
|
324
482
|
}),
|
|
325
483
|
);
|
|
326
484
|
}
|
|
327
485
|
|
|
328
|
-
if (
|
|
329
|
-
log.
|
|
486
|
+
if (iosProjectPath != null) {
|
|
487
|
+
log.title("🍏", "iOS");
|
|
330
488
|
|
|
331
|
-
const
|
|
332
|
-
|
|
489
|
+
const storyboardPath = path.resolve(
|
|
490
|
+
iosProjectPath,
|
|
491
|
+
"BootSplash.storyboard",
|
|
492
|
+
);
|
|
333
493
|
|
|
334
|
-
|
|
335
|
-
|
|
494
|
+
fs.writeFileSync(
|
|
495
|
+
storyboardPath,
|
|
496
|
+
getStoryboard({
|
|
497
|
+
logoHeight,
|
|
498
|
+
logoWidth,
|
|
499
|
+
background: background.rgb,
|
|
500
|
+
}),
|
|
501
|
+
"utf-8",
|
|
502
|
+
);
|
|
336
503
|
|
|
337
|
-
|
|
338
|
-
storyboardPath,
|
|
339
|
-
getStoryboard({
|
|
340
|
-
height: logoHeight,
|
|
341
|
-
width: logoWidth,
|
|
342
|
-
backgroundColor: backgroundColorHex,
|
|
343
|
-
}),
|
|
344
|
-
"utf-8",
|
|
345
|
-
);
|
|
504
|
+
logWrite(storyboardPath);
|
|
346
505
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
506
|
+
const imageSetPath = path.resolve(
|
|
507
|
+
iosProjectPath,
|
|
508
|
+
"Images.xcassets",
|
|
509
|
+
"BootSplashLogo.imageset",
|
|
510
|
+
);
|
|
353
511
|
|
|
354
|
-
|
|
355
|
-
const imageSetPath = path.resolve(imagesPath, xcassetName + ".imageset");
|
|
356
|
-
fs.ensureDirSync(imageSetPath);
|
|
512
|
+
fs.ensureDirSync(imageSetPath);
|
|
357
513
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
514
|
+
fs.writeFileSync(
|
|
515
|
+
path.resolve(imageSetPath, "Contents.json"),
|
|
516
|
+
ContentsJson,
|
|
517
|
+
"utf-8",
|
|
518
|
+
);
|
|
363
519
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
`No "${imagesPath}" directory found. Skipping iOS images generation…`,
|
|
386
|
-
);
|
|
387
|
-
}
|
|
520
|
+
await Promise.all(
|
|
521
|
+
[
|
|
522
|
+
{ ratio: 1, suffix: "" },
|
|
523
|
+
{ ratio: 2, suffix: "@2x" },
|
|
524
|
+
{ ratio: 3, suffix: "@3x" },
|
|
525
|
+
].map(({ ratio, suffix }) => {
|
|
526
|
+
const filePath = path.resolve(
|
|
527
|
+
imageSetPath,
|
|
528
|
+
`bootsplash_logo${suffix}.png`,
|
|
529
|
+
);
|
|
530
|
+
|
|
531
|
+
return logo
|
|
532
|
+
.clone()
|
|
533
|
+
.resize(logoWidth * ratio)
|
|
534
|
+
.png({ quality: 100 })
|
|
535
|
+
.toFile(filePath)
|
|
536
|
+
.then(({ width, height }) => {
|
|
537
|
+
logWrite(filePath, { width, height });
|
|
538
|
+
});
|
|
539
|
+
}),
|
|
540
|
+
);
|
|
388
541
|
}
|
|
389
542
|
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
543
|
+
if (assetsOutputPath != null) {
|
|
544
|
+
log.title("📄", "Assets");
|
|
545
|
+
|
|
546
|
+
fs.ensureDirSync(assetsOutputPath);
|
|
547
|
+
|
|
548
|
+
const manifest: Manifest = {
|
|
549
|
+
background: background.hex,
|
|
550
|
+
logo: {
|
|
551
|
+
width: logoWidth,
|
|
552
|
+
height: logoHeight,
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
|
|
556
|
+
const manifestPath = path.resolve(
|
|
557
|
+
assetsOutputPath,
|
|
558
|
+
"bootsplash_manifest.json",
|
|
559
|
+
);
|
|
560
|
+
|
|
561
|
+
fs.writeFileSync(
|
|
562
|
+
manifestPath,
|
|
563
|
+
JSON.stringify(manifest, null, 2) + "\n",
|
|
564
|
+
"utf-8",
|
|
565
|
+
);
|
|
566
|
+
|
|
567
|
+
logWrite(manifestPath);
|
|
568
|
+
|
|
569
|
+
await Promise.all(
|
|
570
|
+
[
|
|
571
|
+
{ ratio: 1, suffix: "" },
|
|
572
|
+
{ ratio: 1.5, suffix: "@1,5x" },
|
|
573
|
+
{ ratio: 2, suffix: "@2x" },
|
|
574
|
+
{ ratio: 3, suffix: "@3x" },
|
|
575
|
+
{ ratio: 4, suffix: "@4x" },
|
|
576
|
+
].map(({ ratio, suffix }) => {
|
|
577
|
+
const filePath = path.resolve(
|
|
578
|
+
assetsOutputPath,
|
|
579
|
+
`bootsplash_logo${suffix}.png`,
|
|
580
|
+
);
|
|
581
|
+
|
|
582
|
+
return logo
|
|
583
|
+
.clone()
|
|
584
|
+
.resize(Math.round(logoWidth * ratio))
|
|
585
|
+
.png({ quality: 100 })
|
|
586
|
+
.toFile(filePath)
|
|
587
|
+
.then(({ width, height }) => {
|
|
588
|
+
logWrite(filePath, { width, height });
|
|
589
|
+
});
|
|
590
|
+
}),
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
if (licenseKey != null && executeAddon) {
|
|
595
|
+
const addon = requireAddon();
|
|
596
|
+
|
|
597
|
+
await addon?.execute({
|
|
598
|
+
licenseKey,
|
|
599
|
+
|
|
600
|
+
androidResPath,
|
|
601
|
+
iosProjectPath,
|
|
602
|
+
assetsOutputPath,
|
|
603
|
+
|
|
604
|
+
logoHeight,
|
|
605
|
+
logoWidth,
|
|
606
|
+
brandHeight,
|
|
607
|
+
brandWidth,
|
|
608
|
+
|
|
609
|
+
background,
|
|
610
|
+
brand,
|
|
611
|
+
|
|
612
|
+
darkBackground,
|
|
613
|
+
darkLogo,
|
|
614
|
+
darkBrand,
|
|
615
|
+
});
|
|
616
|
+
} else {
|
|
617
|
+
log.text(`
|
|
618
|
+
${pc.blue("┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓")}
|
|
619
|
+
${pc.blue("┃")} 🔑 ${pc.bold(
|
|
620
|
+
"Get a license key for brand image / dark mode support",
|
|
621
|
+
)} ${pc.blue("┃")}
|
|
622
|
+
${pc.blue("┃")} ${pc.underline(
|
|
623
|
+
"https://zoontek.gumroad.com/l/bootsplash-generator",
|
|
624
|
+
)} ${pc.blue("┃")}
|
|
625
|
+
${pc.blue("┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛")}`);
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
log.text(`\n💖 Thanks for using ${pc.underline("react-native-bootsplash")}`);
|
|
404
629
|
};
|