Skip to content

Commit 8106328

Browse files
sc0ttdav3yimhoffd
authored andcommitted
Add support for the Windows 10 platform (#41)
1 parent cfeca45 commit 8106328

File tree

7 files changed

+158
-3
lines changed

7 files changed

+158
-3
lines changed

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ resources/android/icon
5959
resources/android/splash
6060
resources/ios/icon
6161
resources/ios/splash
62+
resources/windows/icon
63+
resources/windows/splash
6264
```
6365

6466
### Programmatic API

src/__tests__/platform.ts

+31
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,37 @@ describe('cordova-res', () => {
6262
expect(result.resources.length).toEqual(generatedImages.length);
6363
});
6464

65+
it('should run through windows icons with successful result', async () => {
66+
const pipeline: any = { clone: jest.fn(() => pipeline) };
67+
imageMock.resolveSourceImage.mockImplementation(async () => ({ src: 'test.png', image: { src: 'test.png', pipeline, metadata: {} } }));
68+
69+
const result = await platform.run(Platform.WINDOWS, 'resources', {
70+
[ResourceType.ICON]: { sources: ['icon.png'] },
71+
});
72+
73+
const generatedImages = getResourcesConfig(Platform.WINDOWS, ResourceType.ICON).resources;
74+
75+
expect(imageMock.resolveSourceImage).toHaveBeenCalledTimes(1);
76+
expect(imageMock.resolveSourceImage).toHaveBeenCalledWith('windows', 'icon', ['icon.png'], undefined);
77+
expect(imageMock.generateImage).toHaveBeenCalledTimes(generatedImages.length);
78+
79+
for (const generatedImage of generatedImages) {
80+
expect(imageMock.generateImage).toHaveBeenCalledWith(
81+
{
82+
src: path.join('resources', generatedImage.src),
83+
format: generatedImage.format,
84+
width: generatedImage.width,
85+
height: generatedImage.height,
86+
},
87+
expect.anything(),
88+
expect.anything(),
89+
undefined
90+
);
91+
}
92+
93+
expect(result.resources.length).toEqual(generatedImages.length);
94+
});
95+
6596
});
6697

6798
describe('isSupportedPlatform', () => {

src/config.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -84,8 +84,10 @@ export function runConfig(configPath: string, resources: ReadonlyArray<Generated
8484

8585
for (const [ platform, platformResources ] of platforms) {
8686
const platformElement = resolvePlatformElement(root, platform);
87-
const filteredResources = platformResources.filter(img => orientation === 'default' || typeof img.orientation === 'undefined' || img.orientation === orientation);
88-
87+
let filteredResources = platformResources.filter(img => orientation === 'default' || typeof img.orientation === 'undefined' || img.orientation === orientation);
88+
if (platform === Platform.WINDOWS) {
89+
filteredResources = filteredResources.filter(img => typeof img.target === 'string');
90+
}
8991
for (const resource of filteredResources) {
9092
runResource(configPath, resource, platformElement);
9193
}

src/image.ts

+4
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,10 @@ export interface ImageSchema {
7171
export async function generateImage(image: ImageSchema, src: Sharp, metadata: Metadata, errstream?: NodeJS.WritableStream): Promise<void> {
7272
debug('Generating %o (%ox%o)', image.src, image.width, image.height);
7373

74+
if (image.format === Format.NONE) {
75+
return;
76+
}
77+
7478
if (errstream) {
7579
if (metadata.format !== image.format) {
7680
errstream.write(`WARN: Must perform conversion from ${metadata.format} to png.\n`);

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface ResultResource {
2323
height?: number;
2424
density?: Density;
2525
orientation?: Orientation;
26+
target?: string;
2627
}
2728

2829
interface ResultSource {
@@ -38,6 +39,7 @@ async function CordovaRes({
3839
platforms = {
3940
[Platform.ANDROID]: generateRunOptions(Platform.ANDROID, resourcesDirectory, []),
4041
[Platform.IOS]: generateRunOptions(Platform.IOS, resourcesDirectory, []),
42+
[Platform.WINDOWS]: generateRunOptions(Platform.WINDOWS, resourcesDirectory, []),
4143
},
4244
}: CordovaRes.Options = {}): Promise<Result> {
4345
const configPath = path.resolve(directory, 'config.xml');

src/platform.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ const debug = Debug('cordova-res:platform');
1111
export const enum Platform {
1212
ANDROID = 'android',
1313
IOS = 'ios',
14+
WINDOWS = 'windows',
1415
}
1516

16-
export const PLATFORMS: ReadonlyArray<Platform> = [Platform.ANDROID, Platform.IOS];
17+
export const PLATFORMS: ReadonlyArray<Platform> = [Platform.ANDROID, Platform.IOS, Platform.WINDOWS];
1718

1819
export interface GeneratedResource extends ResourceKeyValues {
1920
type: ResourceType;

src/resources.ts

+113
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,23 @@ export const enum SourceType {
2424
// TODO: support vectors via Android XML
2525
}
2626

27+
/**
28+
* Windows targets
29+
* @see https://cordova.apache.org/docs/en/latest/config_ref/images.html#windows
30+
*
31+
*/
32+
export const enum WindowsTarget {
33+
STORE_LOGO = 'StoreLogo',
34+
SQUARE_30_X_30_LOGO = 'Square30x30Logo',
35+
SQUARE_44_X_44_LOGO = 'Square44x44Logo',
36+
SQUARE_70_X_70_LOGO = 'Square70x70Logo',
37+
SQUARE_71_X_71_LOGO = 'Square71x71Logo',
38+
SQUARE_150_X_150_LOGO = 'Square150x150Logo',
39+
SQUARE_310_X_310_LOGO = 'Square310x310Logo',
40+
WIDE_310_X_150_LOGO = 'Wide310x150Logo',
41+
SPLASH_SCREEN = 'SplashScreen',
42+
}
43+
2744
export interface ImageSource {
2845
type: SourceType.RASTER;
2946

@@ -119,6 +136,7 @@ export const RASTER_RESOURCE_VALIDATORS: { readonly [T in ResourceType]: Resourc
119136
export const enum Format {
120137
PNG = 'png',
121138
JPEG = 'jpeg',
139+
NONE = 'none',
122140
}
123141

124142
export const enum Orientation {
@@ -156,6 +174,7 @@ export const enum ResourceKey {
156174
HEIGHT = 'height',
157175
DENSITY = 'density',
158176
ORIENTATION = 'orientation',
177+
TARGET = 'target',
159178
}
160179

161180
export interface ResourceKeyValues {
@@ -167,6 +186,7 @@ export interface ResourceKeyValues {
167186
readonly [ResourceKey.HEIGHT]?: number;
168187
readonly [ResourceKey.DENSITY]?: Density;
169188
readonly [ResourceKey.ORIENTATION]?: Orientation;
189+
readonly [ResourceKey.TARGET]?: string;
170190
}
171191

172192
export interface ResourcesImageConfig {
@@ -176,6 +196,7 @@ export interface ResourcesImageConfig {
176196
readonly [ResourceKey.HEIGHT]: number;
177197
readonly [ResourceKey.DENSITY]?: Density;
178198
readonly [ResourceKey.ORIENTATION]?: Orientation;
199+
readonly [ResourceKey.TARGET]?: string;
179200
}
180201

181202
export interface AndroidAdaptiveIconConfig {
@@ -237,6 +258,7 @@ const NodeAttributes = {
237258
DENSITY: { key: ResourceKey.DENSITY },
238259
WIDTH: { key: ResourceKey.WIDTH },
239260
HEIGHT: { key: ResourceKey.HEIGHT },
261+
TARGET: { key: ResourceKey.TARGET },
240262
};
241263

242264
export function getResourcesConfig(platform: Platform.ANDROID, type: ResourceType.ADAPTIVE_ICON): ResourcesTypeConfig<AndroidAdaptiveIconConfig>;
@@ -262,6 +284,97 @@ export function getResourcesConfig(platform: Platform, type: ResourceType): Reso
262284
}
263285

264286
const RESOURCES: ResourcesConfig = {
287+
[Platform.WINDOWS]: {
288+
[ResourceType.ICON]: {
289+
resources: [
290+
/* @see https://cordova.apache.org/docs/en/latest/config_ref/images.html#windows */
291+
/* @see https://docs.microsoft.com/en-us/windows/uwp/design/style/app-icons-and-logos */
292+
/* @see https://docs.microsoft.com/en-us/windows/uwp/design/style/app-icons-and-logos#icon-types-locations-and-scale-factors */
293+
294+
/* App Icon: App list in start menu, task bar, task manager */
295+
{ src : 'windows/icon/Square44x44Logo.png', format: Format.NONE, width: 44, height: 44, target: WindowsTarget.SQUARE_44_X_44_LOGO },
296+
{ src : 'windows/icon/Square44x44Logo.scale-100.png', format: Format.PNG, width: 44, height: 44 },
297+
{ src : 'windows/icon/Square44x44Logo.scale-125.png', format: Format.PNG, width: 55, height: 55 },
298+
{ src : 'windows/icon/Square44x44Logo.scale-140.png', format: Format.PNG, width: 62, height: 62 },
299+
{ src : 'windows/icon/Square44x44Logo.scale-150.png', format: Format.PNG, width: 66, height: 66 },
300+
{ src : 'windows/icon/Square44x44Logo.scale-200.png', format: Format.PNG, width: 88, height: 88 },
301+
{ src : 'windows/icon/Square44x44Logo.scale-240.png', format: Format.PNG, width: 106, height: 106 },
302+
{ src : 'windows/icon/Square44x44Logo.scale-400.png', format: Format.PNG, width: 176, height: 176 },
303+
304+
/* Small tile: Start menu */
305+
{ src : 'windows/icon/SmallTile.png', format: Format.NONE, width: 71, height: 71, target: WindowsTarget.SQUARE_71_X_71_LOGO },
306+
{ src : 'windows/icon/SmallTile.scale-100.png', format: Format.PNG, width: 71, height: 71 },
307+
{ src : 'windows/icon/SmallTile.scale-125.png', format: Format.PNG, width: 89, height: 89 },
308+
{ src : 'windows/icon/SmallTile.scale-140.png', format: Format.PNG, width: 99, height: 99 },
309+
{ src : 'windows/icon/SmallTile.scale-150.png', format: Format.PNG, width: 107, height: 107 },
310+
{ src : 'windows/icon/SmallTile.scale-200.png', format: Format.PNG, width: 142, height: 142 },
311+
{ src : 'windows/icon/SmallTile.scale-240.png', format: Format.PNG, width: 170, height: 170 },
312+
{ src : 'windows/icon/SmallTile.scale-400.png', format: Format.PNG, width: 284, height: 284 },
313+
314+
/* Medium Tile: For Start menu, Microsoft Store listing */
315+
{ src : 'windows/icon/Square150x150Logo.png', format: Format.NONE, width: 150, height: 150, target: WindowsTarget.SQUARE_150_X_150_LOGO },
316+
{ src : 'windows/icon/Square150x150Logo.scale-100.png', format: Format.PNG, width: 150, height: 150 },
317+
{ src : 'windows/icon/Square150x150Logo.scale-125.png', format: Format.PNG, width: 188, height: 188 },
318+
{ src : 'windows/icon/Square150x150Logo.scale-140.png', format: Format.PNG, width: 210, height: 210 },
319+
{ src : 'windows/icon/Square150x150Logo.scale-150.png', format: Format.PNG, width: 225, height: 225 },
320+
{ src : 'windows/icon/Square150x150Logo.scale-200.png', format: Format.PNG, width: 300, height: 300 },
321+
{ src : 'windows/icon/Square150x150Logo.scale-240.png', format: Format.PNG, width: 360, height: 360 },
322+
{ src : 'windows/icon/Square150x150Logo.scale-400.png', format: Format.PNG, width: 600, height: 600 },
323+
324+
/* Large Tile: Start Menu */
325+
{ src : 'windows/icon/Square310x310Logo.png', format: Format.NONE, width: 310, height: 310, target: WindowsTarget.SQUARE_310_X_310_LOGO },
326+
{ src : 'windows/icon/Square310x310Logo.scale-100.png', format: Format.PNG, width: 310, height: 310 },
327+
{ src : 'windows/icon/Square310x310Logo.scale-125.png', format: Format.PNG, width: 388, height: 388 },
328+
{ src : 'windows/icon/Square310x310Logo.scale-140.png', format: Format.PNG, width: 434, height: 434 },
329+
{ src : 'windows/icon/Square310x310Logo.scale-150.png', format: Format.PNG, width: 465, height: 465 },
330+
{ src : 'windows/icon/Square310x310Logo.scale-180.png', format: Format.PNG, width: 558, height: 558 },
331+
{ src : 'windows/icon/Square310x310Logo.scale-200.png', format: Format.PNG, width: 620, height: 620 },
332+
{ src : 'windows/icon/Square310x310Logo.scale-400.png', format: Format.PNG, width: 1240, height: 1240 },
333+
334+
/* Wide Tile: Start Menu */
335+
{ src : 'windows/icon/Wide310x150Logo.png', format: Format.NONE, width: 248, height : 120, target: WindowsTarget.WIDE_310_X_150_LOGO },
336+
{ src : 'windows/icon/Wide310x150Logo.scale-80.png', format: Format.PNG, width: 248, height : 120 },
337+
{ src : 'windows/icon/Wide310x150Logo.scale-100.png', format: Format.PNG, width: 310, height : 150 },
338+
{ src : 'windows/icon/Wide310x150Logo.scale-125.png', format: Format.PNG, width: 388, height : 188 },
339+
{ src : 'windows/icon/Wide310x150Logo.scale-140.png', format: Format.PNG, width: 434, height : 210 },
340+
{ src : 'windows/icon/Wide310x150Logo.scale-150.png', format: Format.PNG, width: 465, height : 225 },
341+
{ src : 'windows/icon/Wide310x150Logo.scale-180.png', format: Format.PNG, width: 558, height : 270 },
342+
{ src : 'windows/icon/Wide310x150Logo.scale-200.png', format: Format.PNG, width: 620, height : 300 },
343+
{ src : 'windows/icon/Wide310x150Logo.scale-240.png', format: Format.PNG, width: 744, height : 360 },
344+
{ src : 'windows/icon/Wide310x150Logo.scale-400.png', format: Format.PNG, width: 1240, height : 600 },
345+
346+
/* Store Logo: App installer, Partner Center, the "Report an app" option in the Store, the "Write a review" option in the Store */
347+
{ src : 'windows/icon/StoreLogo.png', format: Format.NONE, width: 50, height: 50, target: WindowsTarget.STORE_LOGO },
348+
{ src : 'windows/icon/StoreLogo.scale-100.png', format: Format.PNG, width: 50, height: 50 },
349+
{ src : 'windows/icon/StoreLogo.scale-125.png', format: Format.PNG, width: 63, height: 63 },
350+
{ src : 'windows/icon/StoreLogo.scale-140.png', format: Format.PNG, width: 70, height: 70 },
351+
{ src : 'windows/icon/StoreLogo.scale-150.png', format: Format.PNG, width: 75, height: 75 },
352+
{ src : 'windows/icon/StoreLogo.scale-180.png', format: Format.PNG, width: 90, height: 90 },
353+
{ src : 'windows/icon/StoreLogo.scale-200.png', format: Format.PNG, width: 100, height: 100 },
354+
{ src : 'windows/icon/StoreLogo.scale-240.png', format: Format.PNG, width: 120, height: 120 },
355+
{ src : 'windows/icon/StoreLogo.scale-400.png', format: Format.PNG, width: 200, height: 200 },
356+
357+
],
358+
nodeName: 'icon',
359+
nodeAttributes: [NodeAttributes.SRC, NodeAttributes.TARGET], /* NodeAttributes.WIDTH, NodeAttributes.HEIGHT, */
360+
indexAttribute: NodeAttributes.SRC,
361+
},
362+
[ResourceType.SPLASH]: {
363+
resources: [
364+
/* @see https://msdn.microsoft.com/en-us/windows/desktop/hh465338 */
365+
/* @see https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-splashscreen/index.html#windows-specific-information */
366+
{ src: 'windows/splash/Splash.png', format: Format.PNG, width: 620, height: 300, orientation: Orientation.LANDSCAPE, target: WindowsTarget.SPLASH_SCREEN },
367+
{ src: 'windows/splash/Splash.scale-100.png', format: Format.PNG, width: 620, height: 300, orientation: Orientation.LANDSCAPE },
368+
{ src: 'windows/splash/Splash.scale-125.png', format: Format.PNG, width: 775, height: 375, orientation: Orientation.LANDSCAPE },
369+
{ src: 'windows/splash/Splash.scale-150.png', format: Format.PNG, width: 930, height: 450, orientation: Orientation.LANDSCAPE },
370+
{ src: 'windows/splash/Splash.scale-200.png', format: Format.PNG, width: 1240, height: 600, orientation: Orientation.LANDSCAPE },
371+
{ src: 'windows/splash/Splash.scale-400.png', format: Format.PNG, width: 2480, height: 1200, orientation: Orientation.LANDSCAPE },
372+
],
373+
nodeName: 'splash',
374+
nodeAttributes: [NodeAttributes.SRC, NodeAttributes.TARGET], /* NodeAttributes.WIDTH, NodeAttributes.HEIGHT, */
375+
indexAttribute: NodeAttributes.SRC,
376+
},
377+
},
265378
[Platform.ANDROID]: {
266379
[ResourceType.ICON]: {
267380
resources: [

0 commit comments

Comments
 (0)