-
- Notifications
You must be signed in to change notification settings - Fork 197
feat: introduce assets generation #3435
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
lib/bootstrap.ts Outdated
| $injector.require("nodeModulesDependenciesBuilder", "./tools/node-modules/node-modules-dependencies-builder"); | ||
| $injector.require("subscriptionService", "./services/subscription-service"); | ||
| | ||
| $injector.requireCommand("generate-icons", "./commands/generate-assets") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've discussed this internally, and we would like to introduce several commands related to the resources of the project. So can you please rename the commands to resources|generate|icons and resources|generate|splashscreens.
We may also introduce shorthands for these commands, for example res|gen|icons, res|gen|splashes, but lets discuss this further.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've agreed the commands to be:
resources|generate|icons resources|generate|splashes There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The usage will be:
tns resources generate icons path_to_image tns resources generate splashes path_to_image --background <color> lib/bootstrap.ts Outdated
| | ||
| $injector.requireCommand("generate-icons", "./commands/generate-assets") | ||
| $injector.requireCommand("generate-splashscreens", "./commands/generate-assets") | ||
| $injector.requirePublic("assetsGenerationService", "./services/assets-generation/assets-generation-service"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
new line at the end of file please
package.json Outdated
| "mobile" | ||
| ], | ||
| "dependencies": { | ||
| "@types/color": "^3.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be in the devDependencies section. Also, can you please use exact version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
npm i --save-dev --save-exact @types/color
package.json Outdated
| "chokidar": "1.7.0", | ||
| "cli-table": "https://github.com/telerik/cli-table/tarball/v0.3.1.2", | ||
| "clui": "0.3.1", | ||
| "color": "^3.0.0", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Strict version, please (you can use npm i --save --save-exact color in order to update package.json and npm-shrinkwrap.json correctly)
package.json Outdated
| "ios-device-lib": "0.4.10", | ||
| "ios-mobileprovision-finder": "1.0.10", | ||
| "ios-sim-portable": "3.3.0", | ||
| "jimp": "^0.2.28", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, strict version please
| } | ||
| | ||
| @exported("assetsGenerationService") | ||
| public async generateIcons(imagePath: string, resourcesPath: string): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use object as single argument (you'll have to introduce interface for it). This will allow us to handle future changes easier
| } | ||
| | ||
| @exported("assetsGenerationService") | ||
| public async generateSplashScreens(imagePath: string, resourcesPath: string, background?: string): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you use object as single argument (you'll have to introduce interface for it). This will allow us to handle future changes easier
| | ||
| private generateImage(background: string, width: number, height: number, outputPath: string, overlayImage?: Jimp) { | ||
| //Typescript declarations for Jimp are not updated to define the constructor with backgroundColor so we workaround it by casting it to <any> for this case only. | ||
| let J = <any>Jimp; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should be const
| } | ||
| } | ||
| | ||
| private async resize(imagePath: string, width: number, height: number) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method needs return type
| return image.scaleToFit(width, height); | ||
| } | ||
| | ||
| private generateImage(background: string, width: number, height: number, outputPath: string, overlayImage?: Jimp) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this method needs return type. Also can you use a single object for parameter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not part of the public interface and I think it will be better to leave it as it is.
| @ivanovit @rosen-vladimirov |
18398b8 to 6f03ed7 Compare | ping @rosen-vladimirov @Pip3r4o |
rosen-vladimirov left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! 🎉 💯 🥇
petekanev left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for addressing that comment!
| @exported("assetsGenerationService") | ||
| public async generateIcons(resourceGenerationData: IResourceGenerationData): Promise<void> { | ||
| this.$logger.info("Generating icons ..."); | ||
| await this.generateImagesForDefinitions(resourceGenerationData.imagePath, resourceGenerationData.resourcesPath, Icons, resourceGenerationData.platform); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the platform argument should be fifth
622cef1 to 79d618f Compare | public async generateIcons(resourceGenerationData: IResourceGenerationData): Promise<void> { | ||
| this.$logger.info("Generating icons ..."); | ||
| await this.generateImagesForDefinitions(resourceGenerationData.imagePath, resourceGenerationData.resourcesPath, Icons); | ||
| await this.generateImagesForDefinitions(resourceGenerationData.imagePath, resourceGenerationData.resourcesPath, Icons, resourceGenerationData.platform); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we introduce an interface and pass object as param?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As it is a private method and I have some concerns about polluting the .d.fs only for this method I will leave it as it is.
79d618f to 6461ac3 Compare | super($options, $injector, $projectData, $stringParameterBuilder, $assetsGenerationService); | ||
| } | ||
| | ||
| protected async generate(imagePath: string, background?: string): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The second argument here is unnecessary and could be omitted (I think it would still conform to the signature of the Base command)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer to keep it just to ensure the same signature
lib/commands/generate-assets.ts Outdated
| super($options, $injector, $projectData, $stringParameterBuilder, $assetsGenerationService); | ||
| } | ||
| | ||
| protected async generate(imagePath: string, resourcesPath: string, background?: string): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The signature of the base method differs from this one and the third argument will never be passed - I think we'd need to delete resourcesPath: string as a whole?
lib/declarations.d.ts Outdated
| liveEdit: boolean; | ||
| chrome: boolean; | ||
| inspector: boolean; // the counterpart to --chrome | ||
| background: string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing ;
| @@ -0,0 +1,122 @@ | |||
| import * as Jimp from "jimp"; | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the pascal case - this is actually an instance object and should be camelCase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is used as a constructor, so it makes sense to be with pascal case
| this.$logger.info("Splash screens generation completed."); | ||
| } | ||
| | ||
| private async generateImagesForDefinitions(data: IGenerateImagesData): Promise<void> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could accept data: IResourceGenerationData, propertiesToEnumerate: string[] here in order to avoid casting to IGenerateImagesData in the caller methods above.
This is purely cosmetic and not a merge-stopper at all
| const assetsStructure = await this.$projectDataService.getAssetsStructure({ projectDir: data.projectDir }); | ||
| | ||
| for (const platform in assetsStructure) { | ||
| if (data.platform && platform.toLowerCase() !== data.platform.toLowerCase()) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of this whole logic you can construct the required array (an array of values gotten from assetsStructure) using the lodash filter.
You could filter out all the unneeded platforms and items that do not include imageTypeKey.
You would then be able to skip all the continue statements that simulate filtering
lib/services/project-data-service.ts Outdated
| | ||
| const imageDefinitions = this.getImageDefinitions().ios; | ||
| | ||
| if (content && content.images) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can skip this check since you're using the lodash each method - it could just be:
_.each(content && content.images, image => {
| _.each(assetItems, assetItem => { | ||
| _.each(normalizedPaths, currentNormalizedPath => { | ||
| const imagePath = path.join(assetItem.directory, assetItem.filename); | ||
| if (currentNormalizedPath.indexOf(path.normalize(imagePath)) !== -1) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can use _.find to locate the value of interest instead of using _.each and then return false (e.g. break)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've used find at the beginning, but it looks strange, so I prefer the each
lib/services/project-data-service.ts Outdated
| }; | ||
| } | ||
| | ||
| private getImageDefinitions(): any { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this method returns IAssetsStructure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unfortunately it does not :(
lib/services/project-data-service.ts Outdated
| } | ||
| } else { | ||
| // Find the image size based on the hardcoded values in the image-definitions.json | ||
| _.each(imageDefinitions, (assetSubGroup: IAssetItem[]) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You shouldn't need to point the type of assetSubGroup out if imageDefinitions was strongly typed - I believe its type is actually IAssetsStructure
Introduce ``generate-icons`` and ``generate-splashscreens`` commands to generate assets needed for iOS and Android. The operations are as follow: - Icons: - For all platforms we just resize the provided image. - Splash screens: - For Android we generate 2 png for each dpi: blank with background(background.png) and resized image based on provided image(logo.png). During the app start the logo overlays the background. - For iOS we generate 1 png for each dpi which has resized and centered image on the background. All resources with corresponding sizes and operations are described in image-definitions.ts. Added image-generation-test.png in order to provide easy way to test this functionality. For image resizing we use https://github.com/oliver-moran/jimp.
Introduce new methods in `projectDataService` to get the current assets strucuture. Use a predefined .json file in the resources to get information about image sizes. For iOS read the Contents.json file in specific iOS Resource directories. For Android - enumerate the files and construct required objects. Use the new method in the assetsGenerationService. Generate icons and splashes based on the argument. Require projectDir instead of resourcesDir for assets generation in order to get all CLI's specific files info (nsconfig, package.json, project location, etc.). Fix comands for generating assets to have mandatory command parameter - previously it had a non-mandatory param. Add newly exposed methods to the tests.
00ad6ba to d5bfec2 Compare | | ||
| for (const assetItem of assetItems) { | ||
| const operation = assetItem.resizeOperation || Operations.Resize; | ||
| const scale = assetItem.scale || 0.8; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The scale option must be respected for the Resize operation as well. The scale must be parsed to string because the value there is 1x, 2x.
| .value(); | ||
| | ||
| for (const assetItem of assetItems) { | ||
| const operation = assetItem.resizeOperation || Operations.Resize; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you infer the image operation for the asset only from Content.json?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is taken in project-data-service for Android, but I've missed to set it for iOS 😿
Introduce
assets generate iconsandassets generate splashescommands to generate assets needed for iOS and Android.The operations are as follow:
All resources with corresponding sizes and operations are described in image-definitions.ts.
Added image-generation-test.png in order to provide an easy way to test this functionality.
For image resizing we use https://github.com/oliver-moran/jimp.