-
-
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
@@ -144,3 +144,7 @@ $injector.requirePublic("extensibilityService", "./services/extensibility-servic | |||
|
|||
$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
@@ -30,13 +30,15 @@ | |||
"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
"bplist-parser": "0.1.0", | ||
"bufferpack": "0.0.6", | ||
"byline": "4.2.1", | ||
"chalk": "1.1.0", | ||
"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
@@ -48,6 +50,7 @@ | |||
"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 |
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! 🎉 💯 🥇
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
@@ -12,21 +12,23 @@ export class AssetsGenerationService implements IAssetsGenerationService { | |||
@exported("assetsGenerationService") | |||
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
@@ -463,6 +463,7 @@ interface IOptions extends ICommonOptions, IBundleString, IPlatformTemplate, IEm | |||
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 platform
s 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 icons
andassets generate splashes
commands 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.