From 367bb2863394e49ea97982869cd1591fe35b8b86 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Tue, 3 May 2022 19:29:14 +0000 Subject: [PATCH 1/7] feat: Updated `ns generate icons` to be compatible with android `ic_launcher`. --- .../assets-generation-service.ts | 17 +++++ resources/assets/image-definitions.json | 76 ++++++++++++++----- 2 files changed, 76 insertions(+), 17 deletions(-) diff --git a/lib/services/assets-generation/assets-generation-service.ts b/lib/services/assets-generation/assets-generation-service.ts index 898a79237c..75c84ccf70 100644 --- a/lib/services/assets-generation/assets-generation-service.ts +++ b/lib/services/assets-generation/assets-generation-service.ts @@ -20,6 +20,7 @@ export const enum Operations { OverlayWith = "overlayWith", Blank = "blank", Resize = "resize", + OuterScale = "outerScale", } export class AssetsGenerationService implements IAssetsGenerationService { @@ -151,6 +152,22 @@ export class AssetsGenerationService implements IAssetsGenerationService { case Operations.Resize: image = await this.resize(generationData.imagePath, width, height); break; + case Operations.OuterScale: + // Resize image without applying scale + image = await this.resize( + generationData.imagePath, + assetItem.width, + assetItem.height + ); + // The scale will apply to the underlying layer of the generated image + image = this.generateImage( + "#00000000", + width, + height, + outputPath, + image + ); + break; default: throw new Error(`Invalid image generation operation: ${operation}`); } diff --git a/resources/assets/image-definitions.json b/resources/assets/image-definitions.json index 78e1e7eb5b..ba3fb382ae 100644 --- a/resources/assets/image-definitions.json +++ b/resources/assets/image-definitions.json @@ -416,39 +416,81 @@ { "width": 72, "height": 72, - "directory": "drawable-hdpi", - "filename": "icon.png" - }, - { - "width": 36, - "height": 36, - "directory": "drawable-ldpi", - "filename": "icon.png" + "directory": "mipmap-hdpi", + "filename": "ic_launcher.png" }, { "width": 48, "height": 48, - "directory": "drawable-mdpi", - "filename": "icon.png" + "directory": "mipmap-mdpi", + "filename": "ic_launcher.png" }, { "width": 96, "height": 96, - "directory": "drawable-xhdpi", - "filename": "icon.png" + "directory": "mipmap-xhdpi", + "filename": "ic_launcher.png" }, { "width": 144, "height": 144, + "directory": "mipmap-xxhdpi", + "filename": "ic_launcher.png" + }, + { + "width": 192, + "height": 192, + "directory": "mipmap-xxxhdpi", + "filename": "ic_launcher.png" + }, + { + "width": 108, + "height": 108, + "directory": "drawable-hdpi", + "filename": "ic_launcher_foreground.png", + "resizeOperation": "outerScale", + "scale": "1.5x" + }, + { + "width": 54, + "height": 54, + "directory": "drawable-ldpi", + "filename": "ic_launcher_foreground.png", + "resizeOperation": "outerScale", + "scale": "1.5x" + }, + { + "width": 72, + "height": 72, + "directory": "drawable-mdpi", + "filename": "ic_launcher_foreground.png", + "resizeOperation": "outerScale", + "scale": "1.5x" + }, + { + "width": 144, + "height": 144, + "directory": "drawable-xhdpi", + "filename": "ic_launcher_foreground.png", + "resizeOperation": "outerScale", + "scale": "1.5x" + }, + { + "width": 216, + "height": 216, "directory": "drawable-xxhdpi", - "filename": "icon.png" + "filename": "ic_launcher_foreground.png", + "resizeOperation": "outerScale", + "scale": "1.5x" }, { - "width": 345, - "height": 345, + "width": 288, + "height": 288, "directory": "drawable-xxxhdpi", - "filename": "icon.png" - } + "filename": "ic_launcher_foreground.png", + "resizeOperation": "outerScale", + "scale": "1.5x" + }, ], "splashBackgrounds": [ { From c5d3db4baf2e4e7274e0c0e81b0ce7d48b17a234 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Tue, 3 May 2022 19:36:49 +0000 Subject: [PATCH 2/7] fix: Unexpected token in JSON. --- resources/assets/image-definitions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/image-definitions.json b/resources/assets/image-definitions.json index ba3fb382ae..91bd5dcf7b 100644 --- a/resources/assets/image-definitions.json +++ b/resources/assets/image-definitions.json @@ -490,7 +490,7 @@ "filename": "ic_launcher_foreground.png", "resizeOperation": "outerScale", "scale": "1.5x" - }, + } ], "splashBackgrounds": [ { From d1f7e4ee03ba146539b2d52640d21cb7d058db71 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Wed, 4 May 2022 09:46:25 +0000 Subject: [PATCH 3/7] chore: Show warning in case old image definition is not found in android. --- lib/services/project-data-service.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/services/project-data-service.ts b/lib/services/project-data-service.ts index a734a2590e..02d683e129 100644 --- a/lib/services/project-data-service.ts +++ b/lib/services/project-data-service.ts @@ -456,15 +456,24 @@ export class ProjectDataService implements IProjectDataService { const normalizedPaths = _.map(realPaths, (p) => path.normalize(p)); _.each(assetItems, (assetItem) => { + const imagePath = path.join(assetItem.directory, assetItem.filename); + + let found = false; _.each(normalizedPaths, (currentNormalizedPath) => { - const imagePath = path.join(assetItem.directory, assetItem.filename); if (currentNormalizedPath.indexOf(path.normalize(imagePath)) !== -1) { assetItem.path = currentNormalizedPath; assetItem.size = `${assetItem.width}${AssetConstants.sizeDelimiter}${assetItem.height}`; assetSubGroup.images.push(assetItem); + found = true; return false; } }); + + if (!found) { + this.$logger.warn( + `Didn't find a matching old image definition for file ${imagePath}. This file will be skipped from resources generation.` + ); + } }); return assetSubGroup; From 26abe7fcb055e9c6fa2bf037de049893e7f16c01 Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Mon, 29 Aug 2022 22:19:54 +0000 Subject: [PATCH 4/7] chore: Generate assets regardless of whether old ones exist --- lib/services/project-data-service.ts | 36 ++++++++++------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/lib/services/project-data-service.ts b/lib/services/project-data-service.ts index 02d683e129..5e2c886514 100644 --- a/lib/services/project-data-service.ts +++ b/lib/services/project-data-service.ts @@ -236,18 +236,17 @@ export class ProjectDataService implements IProjectDataService { ? path.join(pathToAndroidDir, SRC_DIR, MAIN_DIR, RESOURCES_DIR) : pathToAndroidDir; - const currentStructure = this.$fs.enumerateFilesInDirectorySync(basePath); const content = this.getImageDefinitions().android; return { - icons: this.getAndroidAssetSubGroup(content.icons, currentStructure), + icons: this.getAndroidAssetSubGroup(content.icons, basePath), splashBackgrounds: this.getAndroidAssetSubGroup( content.splashBackgrounds, - currentStructure + basePath ), splashCenterImages: this.getAndroidAssetSubGroup( content.splashCenterImages, - currentStructure + basePath ), splashImages: null, }; @@ -448,32 +447,21 @@ export class ProjectDataService implements IProjectDataService { private getAndroidAssetSubGroup( assetItems: IAssetItem[], - realPaths: string[] + basePath: string ): IAssetSubGroup { const assetSubGroup: IAssetSubGroup = { images: [], }; - const normalizedPaths = _.map(realPaths, (p) => path.normalize(p)); _.each(assetItems, (assetItem) => { - const imagePath = path.join(assetItem.directory, assetItem.filename); - - let found = false; - _.each(normalizedPaths, (currentNormalizedPath) => { - if (currentNormalizedPath.indexOf(path.normalize(imagePath)) !== -1) { - assetItem.path = currentNormalizedPath; - assetItem.size = `${assetItem.width}${AssetConstants.sizeDelimiter}${assetItem.height}`; - assetSubGroup.images.push(assetItem); - found = true; - return false; - } - }); - - if (!found) { - this.$logger.warn( - `Didn't find a matching old image definition for file ${imagePath}. This file will be skipped from resources generation.` - ); - } + const imagePath = path.join( + basePath, + assetItem.directory, + assetItem.filename + ); + assetItem.path = imagePath; + assetItem.size = `${assetItem.width}${AssetConstants.sizeDelimiter}${assetItem.height}`; + assetSubGroup.images.push(assetItem); }); return assetSubGroup; From 536061f904afb18f972b0485ee48581026d13f1b Mon Sep 17 00:00:00 2001 From: Dimitris - Rafail Katsampas Date: Mon, 29 Aug 2022 22:28:49 +0000 Subject: [PATCH 5/7] chore: Added old asset definitions that were removed in a previous commit --- resources/assets/image-definitions.json | 60 ++++++++++++++++++++----- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/resources/assets/image-definitions.json b/resources/assets/image-definitions.json index 91bd5dcf7b..5fac73f5ac 100644 --- a/resources/assets/image-definitions.json +++ b/resources/assets/image-definitions.json @@ -416,32 +416,38 @@ { "width": 72, "height": 72, - "directory": "mipmap-hdpi", - "filename": "ic_launcher.png" + "directory": "drawable-hdpi", + "filename": "icon.png" + }, + { + "width": 36, + "height": 36, + "directory": "drawable-ldpi", + "filename": "icon.png" }, { "width": 48, "height": 48, - "directory": "mipmap-mdpi", - "filename": "ic_launcher.png" + "directory": "drawable-mdpi", + "filename": "icon.png" }, { "width": 96, "height": 96, - "directory": "mipmap-xhdpi", - "filename": "ic_launcher.png" + "directory": "drawable-xhdpi", + "filename": "icon.png" }, { "width": 144, "height": 144, - "directory": "mipmap-xxhdpi", - "filename": "ic_launcher.png" + "directory": "drawable-xxhdpi", + "filename": "icon.png" }, { - "width": 192, - "height": 192, - "directory": "mipmap-xxxhdpi", - "filename": "ic_launcher.png" + "width": 345, + "height": 345, + "directory": "drawable-xxxhdpi", + "filename": "icon.png" }, { "width": 108, @@ -490,6 +496,36 @@ "filename": "ic_launcher_foreground.png", "resizeOperation": "outerScale", "scale": "1.5x" + }, + { + "width": 72, + "height": 72, + "directory": "mipmap-hdpi", + "filename": "ic_launcher.png" + }, + { + "width": 48, + "height": 48, + "directory": "mipmap-mdpi", + "filename": "ic_launcher.png" + }, + { + "width": 96, + "height": 96, + "directory": "mipmap-xhdpi", + "filename": "ic_launcher.png" + }, + { + "width": 144, + "height": 144, + "directory": "mipmap-xxhdpi", + "filename": "ic_launcher.png" + }, + { + "width": 192, + "height": 192, + "directory": "mipmap-xxxhdpi", + "filename": "ic_launcher.png" } ], "splashBackgrounds": [ From 03ade463c4af86e82691d1d0aaec9ca83cc02f26 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 25 Mar 2023 18:10:47 +0100 Subject: [PATCH 6/7] chore: clean up and fix adaptive icon generation with a legacy fallback --- .../resources/resources-generate-icons.md | 4 ++ lib/commands/generate-assets.ts | 1 + lib/declarations.d.ts | 9 +-- lib/definitions/project.d.ts | 5 ++ .../assets-generation-service.ts | 52 ++++++++++++-- lib/services/project-data-service.ts | 18 ++++- resources/assets/image-definitions.json | 67 +++++++++++++++---- 7 files changed, 128 insertions(+), 28 deletions(-) diff --git a/docs/man_pages/project/configuration/resources/resources-generate-icons.md b/docs/man_pages/project/configuration/resources/resources-generate-icons.md index 60186a5d08..9f4ff21afa 100644 --- a/docs/man_pages/project/configuration/resources/resources-generate-icons.md +++ b/docs/man_pages/project/configuration/resources/resources-generate-icons.md @@ -15,6 +15,10 @@ Usage | Synopsis ------|------- `$ tns resources generate icons ` | Generate all icons for Android and iOS based on the specified image. +### Options + +* `--background` Sets the background color of the icon. When no color is specified, a default value of `transparent` is used. `` is a valid color and can be represented with string, like `white`, `black`, `blue`, or with HEX representation, for example `#FFFFFF`, `#000000`, `#0000FF`. NOTE: As the `#` is special symbol in some terminals, make sure to place the value in quotes, for example `$ tns resources generate icons ../myImage.png --background "#FF00FF"`. + ### Arguments * `` is a valid path to an image that will be used to generate all icons. diff --git a/lib/commands/generate-assets.ts b/lib/commands/generate-assets.ts index b7c9e9cff5..5133cea3e0 100644 --- a/lib/commands/generate-assets.ts +++ b/lib/commands/generate-assets.ts @@ -61,6 +61,7 @@ export class GenerateIconsCommand ): Promise { await this.$assetsGenerationService.generateIcons({ imagePath, + background, projectDir: this.$projectData.projectDir, }); } diff --git a/lib/declarations.d.ts b/lib/declarations.d.ts index 1e22ea542a..9de868d95c 100644 --- a/lib/declarations.d.ts +++ b/lib/declarations.d.ts @@ -1144,12 +1144,7 @@ interface IResourceGenerationData extends IProjectDir { * @param {string} platform Specify for which platform to generate assets. If not defined will generate for all platforms */ platform?: string; -} -/** - * Describes the data needed for splash screens generation - */ -interface ISplashesGenerationData extends IResourceGenerationData { /** * @param {string} background Background color that will be used for background. Defaults to #FFFFFF */ @@ -1169,11 +1164,11 @@ interface IAssetsGenerationService { /** * Generate splash screens for iOS and Android - * @param {ISplashesGenerationData} splashesGenerationData Provides the data needed for splash screens generation + * @param {IResourceGenerationData} splashesGenerationData Provides the data needed for splash screens generation * @returns {Promise} */ generateSplashScreens( - splashesGenerationData: ISplashesGenerationData + splashesGenerationData: IResourceGenerationData ): Promise; } diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index 1885afbe44..92b81934ad 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -407,6 +407,10 @@ interface IAssetItem { resizeOperation?: string; overlayImageScale?: number; rgba?: boolean; + + // additional operations for special cases + operation?: "delete" | "writeXMLColor"; + data?: any; } interface IAssetSubGroup { @@ -438,6 +442,7 @@ interface IImageDefinitionGroup { interface IImageDefinitionsStructure { ios: IImageDefinitionGroup; android: IImageDefinitionGroup; + android_legacy: IImageDefinitionGroup; } interface ITemplateData { diff --git a/lib/services/assets-generation/assets-generation-service.ts b/lib/services/assets-generation/assets-generation-service.ts index 75c84ccf70..561ba6993c 100644 --- a/lib/services/assets-generation/assets-generation-service.ts +++ b/lib/services/assets-generation/assets-generation-service.ts @@ -5,16 +5,16 @@ import { AssetConstants } from "../../constants"; import { IAssetsGenerationService, IResourceGenerationData, - ISplashesGenerationData, } from "../../declarations"; import { IProjectDataService, IAssetGroup, IAssetSubGroup, } from "../../definitions/project"; -import { IDictionary } from "../../common/declarations"; +import { IDictionary, IFileSystem } from "../../common/declarations"; import * as _ from "lodash"; import { injector } from "../../common/yok"; +import { EOL } from "os"; export const enum Operations { OverlayWith = "overlayWith", @@ -33,7 +33,8 @@ export class AssetsGenerationService implements IAssetsGenerationService { constructor( private $logger: ILogger, - private $projectDataService: IProjectDataService + private $projectDataService: IProjectDataService, + private $fs: IFileSystem ) {} @exported("assetsGenerationService") @@ -50,7 +51,7 @@ export class AssetsGenerationService implements IAssetsGenerationService { @exported("assetsGenerationService") public async generateSplashScreens( - splashesGenerationData: ISplashesGenerationData + splashesGenerationData: IResourceGenerationData ): Promise { this.$logger.info("Generating splash screens ..."); await this.generateImagesForDefinitions( @@ -61,10 +62,10 @@ export class AssetsGenerationService implements IAssetsGenerationService { } private async generateImagesForDefinitions( - generationData: ISplashesGenerationData, + generationData: IResourceGenerationData, propertiesToEnumerate: string[] ): Promise { - generationData.background = generationData.background || "white"; + // generationData.background = generationData.background || "white"; const assetsStructure = await this.$projectDataService.getAssetsStructure( generationData ); @@ -89,6 +90,45 @@ export class AssetsGenerationService implements IAssetsGenerationService { .value(); for (const assetItem of assetItems) { + if (assetItem.operation === "delete") { + if (this.$fs.exists(assetItem.path)) { + this.$fs.deleteFile(assetItem.path); + } + continue; + } + + if (assetItem.operation === "writeXMLColor") { + const colorName = assetItem.data?.colorName; + if (!colorName) { + continue; + } + try { + const color = + (generationData as any)[assetItem.data?.fromKey] ?? + assetItem.data?.default ?? + "white"; + + const colorHEX: number = Jimp.cssColorToHex(color); + const hex = colorHEX?.toString(16).substring(0, 6) ?? "FFFFFF"; + + this.$fs.writeFile( + assetItem.path, + [ + ``, + ``, + ` #${hex.toUpperCase()}`, + ``, + ].join(EOL) + ); + } catch (err) { + this.$logger.info( + `Failed to write provided color to ${assetItem.path} -> ${colorName}. See --log trace for more info.` + ); + this.$logger.trace(err); + } + continue; + } + const operation = assetItem.resizeOperation || Operations.Resize; let tempScale: number = null; if (assetItem.scale) { diff --git a/lib/services/project-data-service.ts b/lib/services/project-data-service.ts index 5e2c886514..abc917c424 100644 --- a/lib/services/project-data-service.ts +++ b/lib/services/project-data-service.ts @@ -236,7 +236,19 @@ export class ProjectDataService implements IProjectDataService { ? path.join(pathToAndroidDir, SRC_DIR, MAIN_DIR, RESOURCES_DIR) : pathToAndroidDir; - const content = this.getImageDefinitions().android; + let useLegacy = false; + try { + const manifest = this.$fs.readText( + path.resolve(basePath, "../AndroidManifest.xml") + ); + useLegacy = !manifest.includes(`android:icon="@mipmap/ic_launcher"`); + } catch (err) { + // ignore + } + + const content = this.getImageDefinitions()[ + useLegacy ? "android_legacy" : "android" + ]; return { icons: this.getAndroidAssetSubGroup(content.icons, basePath), @@ -460,7 +472,9 @@ export class ProjectDataService implements IProjectDataService { assetItem.filename ); assetItem.path = imagePath; - assetItem.size = `${assetItem.width}${AssetConstants.sizeDelimiter}${assetItem.height}`; + if (assetItem.width && assetItem.height) { + assetItem.size = `${assetItem.width}${AssetConstants.sizeDelimiter}${assetItem.height}`; + } assetSubGroup.images.push(assetItem); }); diff --git a/resources/assets/image-definitions.json b/resources/assets/image-definitions.json index 5fac73f5ac..d3bc47cd6d 100644 --- a/resources/assets/image-definitions.json +++ b/resources/assets/image-definitions.json @@ -411,43 +411,74 @@ } ] }, - "android": { + "android_legacy": { "icons": [ { "width": 72, "height": 72, "directory": "drawable-hdpi", - "filename": "icon.png" + "filename": "icon.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 36, "height": 36, "directory": "drawable-ldpi", - "filename": "icon.png" + "filename": "icon.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 48, "height": 48, "directory": "drawable-mdpi", - "filename": "icon.png" + "filename": "icon.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 96, "height": 96, "directory": "drawable-xhdpi", - "filename": "icon.png" + "filename": "icon.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 144, "height": 144, "directory": "drawable-xxhdpi", - "filename": "icon.png" + "filename": "icon.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 345, "height": 345, "directory": "drawable-xxxhdpi", - "filename": "icon.png" + "filename": "icon.png", + "resizeOperation": "overlayWith", + "scale": "1x" + } + ] + }, + "android": { + "icons": [ + { + "directory": "drawable", + "filename": "ic_launcher_foreground.xml", + "operation": "delete" + }, + { + "directory": "values", + "filename": "ic_launcher_background.xml", + "operation": "writeXMLColor", + "data": { + "colorName": "ic_launcher_background", + "fromKey": "background", + "default": "#FFFFFF" + } }, { "width": 108, @@ -501,31 +532,41 @@ "width": 72, "height": 72, "directory": "mipmap-hdpi", - "filename": "ic_launcher.png" + "filename": "ic_launcher.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 48, "height": 48, "directory": "mipmap-mdpi", - "filename": "ic_launcher.png" + "filename": "ic_launcher.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 96, "height": 96, "directory": "mipmap-xhdpi", - "filename": "ic_launcher.png" + "filename": "ic_launcher.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 144, "height": 144, "directory": "mipmap-xxhdpi", - "filename": "ic_launcher.png" + "filename": "ic_launcher.png", + "resizeOperation": "overlayWith", + "scale": "1x" }, { "width": 192, "height": 192, "directory": "mipmap-xxxhdpi", - "filename": "ic_launcher.png" + "filename": "ic_launcher.png", + "resizeOperation": "overlayWith", + "scale": "1x" } ], "splashBackgrounds": [ @@ -611,4 +652,4 @@ } ] } -} \ No newline at end of file +} From d27e521e56b88df416c4609b419a67c1031abf21 Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Sat, 25 Mar 2023 18:13:24 +0100 Subject: [PATCH 7/7] chore: cleanup --- .../assets-generation/assets-generation-service.ts | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/lib/services/assets-generation/assets-generation-service.ts b/lib/services/assets-generation/assets-generation-service.ts index 561ba6993c..56cab34623 100644 --- a/lib/services/assets-generation/assets-generation-service.ts +++ b/lib/services/assets-generation/assets-generation-service.ts @@ -65,7 +65,7 @@ export class AssetsGenerationService implements IAssetsGenerationService { generationData: IResourceGenerationData, propertiesToEnumerate: string[] ): Promise { - // generationData.background = generationData.background || "white"; + const background = generationData.background || "white"; const assetsStructure = await this.$projectDataService.getAssetsStructure( generationData ); @@ -174,7 +174,7 @@ export class AssetsGenerationService implements IAssetsGenerationService { imageResize ); image = this.generateImage( - generationData.background, + background, width, height, outputPath, @@ -182,12 +182,7 @@ export class AssetsGenerationService implements IAssetsGenerationService { ); break; case Operations.Blank: - image = this.generateImage( - generationData.background, - width, - height, - outputPath - ); + image = this.generateImage(background, width, height, outputPath); break; case Operations.Resize: image = await this.resize(generationData.imagePath, width, height);