Skip to content

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

Merged
merged 10 commits into from
Mar 21, 2018
4 changes: 3 additions & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@
// "args": [ "run", "android", "--path", "cliapp"]
// "args": [ "debug", "android", "--path", "cliapp"]
// "args": [ "livesync", "android", "--path", "cliapp"]
// "args": [ "livesync", "android", "--watch", "--path", "cliapp"]
// "args": [ "livesync", "android", "--watch", "--path", "cliapp"],
// "args": [ "resources", "generate", "icons", "./test/image-generation-test.png", "--path", "cliapp" ],
// "args": [ "resources", "generate", "splashes", "./test/image-generation-test.png", "--path", "cliapp", "--background", "#8000ff" ],
},
{
// in case you want to debug a single test, modify it's code to be `it.only(...` instead of `it(...`
Expand Down
116 changes: 115 additions & 1 deletion PublicAPI.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ const tns = require("nativescript");
* [projectDataService](#projectdataservice)
* [getProjectData](#getprojectdata)
* [getProjectDataFromContent](#getprojectdatafromcontent)
* [getNsConfigDefaultContent](#getnsconfigdefaultcontent)
* [getAssetsStructure](#getassetsstructure)
* [getIOSAssetsStructure](#getiosassetsstructure)
* [getAndroidAssetsStructure](#getandroidassetsstructure)
* [extensibilityService](#extensibilityservice)
* [installExtension](#installextension)
* [uninstallExtension](#uninstallextension)
Expand Down Expand Up @@ -41,7 +45,9 @@ const tns = require("nativescript");
* [analyticsSettingsService](#analyticsSettingsService)
* [getClientId](#getClientId)
* [constants](#constants)

* [assetsGenerationService](#assetsgenerationservice)
* [generateIcons](#generateicons)
* [generateSplashScreens](#generatesplashscreens)

## Module projectService

Expand Down Expand Up @@ -199,6 +205,66 @@ Returns the default content of "nsconfig.json" merged with the properties provid
getNsConfigDefaultContent(data?: Object): string
```

### getAssetsStructure
Gives information about the whole assets structure for both iOS and Android. For each of the platforms, the returned object will contain icons, splashBackgrounds, splashCenterImages and splashImages (only for iOS).
* Definition:
```TypeScript
/**
* Gives information about the whole assets structure for both iOS and Android.
* For each of the platforms, the returned object will contain icons, splashBackgrounds, splashCenterImages and splashImages (only for iOS).
* @param {IProjectDir} opts Object with a single property - projectDir. This is the root directory where NativeScript project is located.
* @returns {Promise<IAssetsStructure>} An object describing the current asset structure.
*/
getAssetsStructure(opts: IProjectDir): Promise<IAssetsStructure>;
```

* Usage:
```JavaScript
tns.projectDataService.getAssetsStructure({ projectDir: "/Users/username/myNativeScriptProject" })
.then(assetsStructure => console.log(`The current assets structure is ${JSON.stringify(assetsStructure, null, 2)}.`))
.catch(err => console.log("Failed to get assets structure."));
```

### getIOSAssetsStructure
Gives information about the assets structure for iOS .The returned object will contain icons, splashBackgrounds, splashCenterImages and splashImages.
* Definition:
```TypeScript
/**
* Gives information about the whole assets structure for iOS.
* The returned object will contain icons, splashBackgrounds, splashCenterImages and splashImages.
* @param {IProjectDir} opts Object with a single property - projectDir. This is the root directory where NativeScript project is located.
* @returns {Promise<IAssetGroup>} An object describing the current asset structure for iOS.
*/
getIOSAssetsStructure(opts: IProjectDir): Promise<IAssetGroup>;
```

* Usage:
```JavaScript
tns.projectDataService.getIOSAssetsStructure({ projectDir: "/Users/username/myNativeScriptProject" })
.then(assetsStructure => console.log(`The current assets structure for iOS is ${JSON.stringify(assetsStructure, null, 2)}.`))
.catch(err => console.log("Failed to get assets structure."));
```

### getAndroidAssetsStructure
Gives information about the assets structure for Android .The returned object will contain icons, splashBackgrounds and splashCenterImages.
* Definition:
```TypeScript
/**
* Gives information about the whole assets structure for Android.
* The returned object will contain icons, splashBackgrounds and splashCenterImages.
* @param {IProjectDir} opts Object with a single property - projectDir. This is the root directory where NativeScript project is located.
* @returns {Promise<IAssetGroup>} An object describing the current asset structure for Android.
*/
getAndroidAssetsStructure(opts: IProjectDir): Promise<IAssetGroup>;
```

* Usage:
```JavaScript
tns.projectDataService.getAndroidAssetsStructure({ projectDir: "/Users/username/myNativeScriptProject" })
.then(assetsStructure => console.log(`The current assets structure for Android is ${JSON.stringify(assetsStructure, null, 2)}.`))
.catch(err => console.log("Failed to get assets structure."));
```

## extensibilityService
`extensibilityService` module gives access to methods for working with CLI's extensions - list, install, uninstall, load them. The extensions add new functionality to CLI, so once an extension is loaded, all methods added to it's public API are accessible directly through CLI when it is used as a library. Extensions may also add new commands, so they are accessible through command line when using NativeScript CLI.

Expand Down Expand Up @@ -1013,6 +1079,54 @@ tns.analyticsSettingsService.getPlaygroundInfo("/my/project/path")
## constants
Contains various constants related to NativeScript.

## assetsGenerationService
`assetsGenerationService` module allows generation of assets - icons and splashes.

### generateIcons
The `generateIcons` method generates icons for specified platform (or both iOS and Android in case platform is not specified) and places them on correct location in the specified project.

* Definition:
```TypeScript
/**
* Generate icons for iOS and Android
* @param {IResourceGenerationData} iconsGenerationData Provides the data needed for icons generation
* @returns {Promise<void>}
*/
generateIcons({ imagePath: string, projectDir: string, platform?: string }): Promise<void>;
```

* Usage:
```JavaScript
tns.assetsGenerationService.generateIcons({ projectDir: "/Users/username/myNativeScriptProject", imagePath: "/Users/username/image.png" })
.then(() => {
console.log("Successfully generated icons");
});
```


### generateSplashScreens
The `generateSplashScreens` method generates icons for specified platform (or both iOS and Android in case platform is not specified) and places them on correct location in the specified project.

* Definition:
```TypeScript
/**
* Generate splash screens for iOS and Android
* @param {ISplashesGenerationData} splashesGenerationData Provides the data needed for splash screens generation
* @returns {Promise<void>}
*/
generateSplashScreens({ imagePath: string, projectDir: string, platform?: string, background?: string }): Promise<void>;
```

* Usage:
```JavaScript
tns.assetsGenerationService.generateSplashScreens({ projectDir: "/Users/username/myNativeScriptProject", imagePath: "/Users/username/image.png", background: "blue" })
.then(() => {
console.log("Successfully generated splash screens");
});
```



## How to add a new method to Public API
CLI is designed as command line tool and when it is used as a library, it does not give you access to all of the methods. This is mainly implementation detail. Most of the CLI's code is created to work in command line, not as a library, so before adding method to public API, most probably it will require some modification.
For example the `$options` injected module contains information about all `--` options passed on the terminal. When the CLI is used as a library, the options are not populated. Before adding method to public API, make sure its implementation does not rely on `$options`.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<% if (isJekyll) { %>---
title: tns resources generate icons
position: 11
---<% } %>
# tns resources generate icons

Usage | Synopsis
------|-------
`$ tns resources generate icons <Path to image>` | Generate all icons for Android and iOS based on the specified image.

Generates all icons for Android and iOS platforms and places the generated images in the correct directories under `App_Resources/<platform>` directory.

### Attributes
* `<Path to image>` is a valid path to an image that will be used to generate all icons.

<% if(isHtml) { %>
### Related Commands

Command | Description
----------|----------
[install](../install.html) | Installs all platforms and dependencies described in the `package.json` file in the current directory.
[platform add](../platform-add.html) | Configures the current project to target the selected platform.
[platform remove](../platform-remove.html) | Removes the selected platform from the platforms that the project currently targets.
[platform](../platform.html) | Lists all platforms that the project currently targets.
[prepare](../prepare.html) | Copies common and relevant platform-specific content from the app directory to the subdirectory for the selected target platform in the platforms directory.
[resources update](resources-update.md) | Updates the `App_Resources/Android` internal folder structure to conform to that of an Android Studio project.
[resources generate splashes](resources-generate-splashes.md) | Generates splashscreens for Android and iOS.
<% } %>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<% if (isJekyll) { %>---
title: tns resources generate splashes
position: 12
---<% } %>
# tns resources generate splashes

Usage | Synopsis
------|-------
`$ tns resources generate splashes <Path to image> [<background>]` | Generate all splashscreens for Android and iOS based on the specified image.

Generates all icons for Android and iOS platforms and places the generated images in the correct directories under `App_Resources/<platform>` directory.

### Attributes
* `<Path to image>` is a valid path to an image that will be used to generate all splashscreens.
* `<background>` is a valid path to an image that will be used as a background of the splashscreen. Defaults to white in case it is not specified.

<% if(isHtml) { %>
### Related Commands

Command | Description
----------|----------
[install](../install.html) | Installs all platforms and dependencies described in the `package.json` file in the current directory.
[platform add](../platform-add.html) | Configures the current project to target the selected platform.
[platform remove](../platform-remove.html) | Removes the selected platform from the platforms that the project currently targets.
[platform](../platform.html) | Lists all platforms that the project currently targets.
[prepare](../prepare.html) | Copies common and relevant platform-specific content from the app directory to the subdirectory for the selected target platform in the platforms directory.
[resources update](resources-update.md) | Updates the `App_Resources/Android` internal folder structure to conform to that of an Android Studio project.
[resources generate icons](resources-generate-icons.md) | Generates icons for Android and iOS.
<% } %>
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
<% if (isJekyll) { %>---
title: tns resources update
position: 9
position: 10
---<% } %>
#tns resources update
# tns resources update
==========

Usage | Synopsis
Expand All @@ -11,7 +11,7 @@ Usage | Synopsis
`$ tns resources update android` | Updates the App_Resources/Android's folder structure.

Updates the App_Resources/<platform>'s internal folder structure to conform to that of an Android Studio project. Android resource files and directories will be located at the following paths:
- `drawable-*`, `values`, `raw`, etc. can be found at `App_Resources/Android/src/main/res`
- `drawable-*`, `values`, `raw`, etc. can be found at `App_Resources/Android/src/main/res`
- `AndroidManifest.xml` can be found at `App_Resources/Android/src/main/AndroidManifest.xml`
- Java source files can be dropped in at `App_Resources/Android/src/main/java` after creating the proper package subdirectory structure
- Additional arbitrary assets can be dropped in at `App_Resources/Android/src/main/assets`
Expand Down
4 changes: 4 additions & 0 deletions lib/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,7 @@ $injector.require("terminalSpinnerService", "./services/terminal-spinner-service
$injector.require('playgroundService', './services/playground-service');
$injector.require("platformEnvironmentRequirements", "./services/platform-environment-requirements");
$injector.require("nativescriptCloudExtensionService", "./services/nativescript-cloud-extension-service");

$injector.requireCommand("resources|generate|icons", "./commands/generate-assets");
$injector.requireCommand("resources|generate|splashes", "./commands/generate-assets");
$injector.requirePublic("assetsGenerationService", "./services/assets-generation/assets-generation-service");
50 changes: 50 additions & 0 deletions lib/commands/generate-assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
export abstract class GenerateCommandBase implements ICommand {
public allowedParameters: ICommandParameter[] = [this.$stringParameterBuilder.createMandatoryParameter("You have to provide path to image to generate other images based on it.")];

constructor(protected $options: IOptions,
protected $injector: IInjector,
protected $projectData: IProjectData,
protected $stringParameterBuilder: IStringParameterBuilder,
protected $assetsGenerationService: IAssetsGenerationService) {
this.$projectData.initializeProjectData();
}

public async execute(args: string[]): Promise<void> {
const [ imagePath ] = args;
await this.generate(imagePath, this.$options.background);
}

protected abstract generate(imagePath: string, background?: string): Promise<void>;
}

export class GenerateIconsCommand extends GenerateCommandBase implements ICommand {
constructor(protected $options: IOptions,
$injector: IInjector,
protected $projectData: IProjectData,
protected $stringParameterBuilder: IStringParameterBuilder,
$assetsGenerationService: IAssetsGenerationService) {
super($options, $injector, $projectData, $stringParameterBuilder, $assetsGenerationService);
}

protected async generate(imagePath: string, background?: string): Promise<void> {
Copy link
Contributor

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)

Copy link
Contributor

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

await this.$assetsGenerationService.generateIcons({ imagePath, projectDir: this.$projectData.projectDir });
}
}

$injector.registerCommand("resources|generate|icons", GenerateIconsCommand);

export class GenerateSplashScreensCommand extends GenerateCommandBase implements ICommand {
constructor(protected $options: IOptions,
$injector: IInjector,
protected $projectData: IProjectData,
protected $stringParameterBuilder: IStringParameterBuilder,
$assetsGenerationService: IAssetsGenerationService) {
super($options, $injector, $projectData, $stringParameterBuilder, $assetsGenerationService);
}

protected async generate(imagePath: string, background?: string): Promise<void> {
await this.$assetsGenerationService.generateSplashScreens({ imagePath, background, projectDir: this.$projectData.projectDir });
}
}

$injector.registerCommand("resources|generate|splashes", GenerateSplashScreensCommand);
15 changes: 15 additions & 0 deletions lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -148,3 +148,18 @@ export const NATIVESCRIPT_CLOUD_EXTENSION_NAME = "nativescript-cloud";
* Used in ProjectDataService to concatenate the names of the properties inside nativescript key of package.json.
*/
export const NATIVESCRIPT_PROPS_INTERNAL_DELIMITER = "**|__**";
export const CLI_RESOURCES_DIR_NAME = "resources";

export class AssetConstants {
public static iOSResourcesFileName = "Contents.json";
public static iOSAssetsDirName = "Assets.xcassets";
public static iOSIconsDirName = "AppIcon.appiconset";
public static iOSSplashBackgroundsDirName = "LaunchScreen.AspectFill.imageset";
public static iOSSplashCenterImagesDirName = "LaunchScreen.Center.imageset";
public static iOSSplashImagesDirName = "LaunchImage.launchimage";

public static imageDefinitionsFileName = "image-definitions.json";
public static assets = "assets";

public static sizeDelimiter = "x";
}
49 changes: 47 additions & 2 deletions lib/declarations.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,7 @@ interface IOptions extends ICommonOptions, IBundleString, IPlatformTemplate, IEm
liveEdit: boolean;
chrome: boolean;
inspector: boolean; // the counterpart to --chrome
background: string;
}

interface IEnvOptions {
Expand Down Expand Up @@ -570,7 +571,7 @@ interface IAndroidToolsInfo {
*/
validateAndroidHomeEnvVariable(options?: IAndroidToolsInfoOptions): boolean;

/**
/**
* Validates target sdk
* @param {IAndroidToolsInfoOptions} options @optional Defines if the warning messages should treated as error.
* @returns {boolean} True if there are detected issues, false otherwise
Expand Down Expand Up @@ -790,7 +791,51 @@ interface IBundleValidatorHelper {
interface INativescriptCloudExtensionService {
/**
* Installs nativescript-cloud extension
* @return {Promise<IExtensionData>} returns the extension data
* @return {Promise<IExtensionData>} returns the extension data
*/
install(): Promise<IExtensionData>;
}

/**
* Describes the basic data needed for resource generation
*/
interface IResourceGenerationData extends IProjectDir {
/**
* @param {string} imagePath Path to the image that will be used for generation
*/
imagePath: string,

/**
* @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
*/
background?: string
}

/**
* Describes service used for assets generation
*/
interface IAssetsGenerationService {
/**
* Generate icons for iOS and Android
* @param {IResourceGenerationData} iconsGenerationData Provides the data needed for icons generation
* @returns {Promise<void>}
*/
generateIcons(iconsGenerationData: IResourceGenerationData): Promise<void>;

/**
* Generate splash screens for iOS and Android
* @param {ISplashesGenerationData} splashesGenerationData Provides the data needed for splash screens generation
* @returns {Promise<void>}
*/
generateSplashScreens(splashesGenerationData: ISplashesGenerationData): Promise<void>;
}
Loading