Skip to content

Commit

Permalink
FigmaExport doesn't delete old resources (Android)
Browse files Browse the repository at this point in the history
Closes #28
  • Loading branch information
subdan committed Sep 23, 2020
1 parent b3f6364 commit a68f506
Show file tree
Hide file tree
Showing 53 changed files with 134 additions and 21 deletions.
6 changes: 6 additions & 0 deletions Examples/AndroidExample/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ android {
kotlinOptions {
jvmTarget = '1.8'
}
sourceSets {
main {
res.srcDirs += "src/main/res/figma-export-icons"
res.srcDirs += "src/main/res/figma-export-images"
}
}
}

dependencies {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
<ImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:srcCompat="@drawable/ic_24_dots"
app:srcCompat="@drawable/ic_24_close"
app:tint="@color/tint" />

<Space
Expand Down
9 changes: 9 additions & 0 deletions Examples/AndroidExample/figma-export.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,18 @@ common:
# Name of the Figma's frame where image components are located
figmaFrameName: Illustrations

# [optional] Android export parameters
android:
# Relative or absolute path to the `main/res` folder including it. The colors/icons/imags will be exported to this folder
mainRes: ./app/src/main/res
# Parameters for exporting icons
icons:
# Where to place icons relative to `mainRes`? FigmaExport clears this directory every time your execute `figma-export icons` command
output: "figma-export-icons"
# Parameters for exporting images
images:
# Where to place images relative to `mainRes`? FigmaExport clears this directory every time your execute `figma-export images` command
output: "figma-export-images"
# Image file format: svg, png or webp
format: webp
# Format options for webp format only
Expand Down
2 changes: 1 addition & 1 deletion FigmaExport.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |spec|
spec.name = "FigmaExport"
spec.version = "0.14.0"
spec.version = "0.14.1"
spec.summary = "Command line utility to export colors, typography, icons and images from Figma to Xcode / Android Studio project."
spec.homepage = "https://github.com/RedMadRobot/figma-export"
spec.license = { type: "MIT", file: "LICENSE" }
Expand Down
39 changes: 39 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ Table of Contents:
- [Homebrew](#homebrew)
- [CocoaPods + Fastlane](#cocoapods--fastlane)
- [Usage](#usage)
- [Android](#android-1)
- [Arguments](#arguments)
- [Configuration](#configuration)
- [Exporting Typography](#exporting-typography)
Expand Down Expand Up @@ -263,6 +264,44 @@ Run `fastlane sync_colors` to run FigmaExport.

`./figma-export typography -i figma-export.yaml`

### Android

In the `figma-export.yaml` file you must specify the following properties:
- `android.mainRes`
- `android.icons.output` if you want export icons
- `android.images.output` if you want export images

When you execute `figma-export icons` command, FigmaExport clears the `{android.mainRes}/{android.icons.output}` directory before exporting all the icons.

When you execute `figma-export images` command, FigmaExport clears the `{android.mainRes}/{android.images.output}` directory before exporting all the images.

Example folder structure:
```
main/
res/
figma-export-icons/
drawable/
drawable-night/
figma-export-images/
drawable/
drawable-night/
```

Before first running `figma-export` you must add path to these directories in the the app‘s `build.gradle` file.

```
...
android {
...
sourceSets {
main {
res.srcDirs += "src/main/res/figma-export-icons"
res.srcDirs += "src/main/res/figma-export-images"
}
}
}
```

### Arguments

If you want to export specific icons/images you can list their names in the last argument like this:
Expand Down
6 changes: 6 additions & 0 deletions Release/figma-export.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,14 @@ ios:
android:
# Relative or absolute path to the `main/res` folder including it. The colors/icons/imags will be exported to this folder
mainRes: "./main/res"
# Parameters for exporting icons
icons:
# Where to place icons relative to `mainRes`? FigmaExport clears this directory every time your execute `figma-export icons` command
output: "figma-export-icons"
# Parameters for exporting images
images:
# Where to place images relative to `mainRes`? FigmaExport clears this directory every time your execute `figma-export images` command
output: "figma-export-images"
# Image file format: svg or png
format: webp
# Format options for webp format only
Expand Down
7 changes: 6 additions & 1 deletion Sources/FigmaExport/Input/Params.swift
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ struct Params: Decodable {
}

struct Android: Decodable {
struct Icons: Decodable {
let output: String
}
struct Images: Decodable {
enum Format: String, Decodable {
case svg
Expand All @@ -98,11 +101,13 @@ struct Params: Decodable {
let encoding: Encoding
let quality: Int?
}
let output: String
let format: Format
let webpOptions: FormatOptions?
}
let mainRes: URL
let images: Images
let icons: Icons?
let images: Images?
}

let figma: Figma
Expand Down
2 changes: 1 addition & 1 deletion Sources/FigmaExport/Loaders/ImagesLoader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ final class ImagesLoader {
}

func loadImages(filter: String? = nil) throws -> (light: [ImagePack], dark: [ImagePack]?) {
switch (platform, params.android?.images.format) {
switch (platform, params.android?.images?.format) {
case (.android, .png), (.android, .webp), (.ios, .none):
let lightImages = try loadPNGImages(
fileId: params.figma.lightFileId,
Expand Down
7 changes: 7 additions & 0 deletions Sources/FigmaExport/Subcommands/ExportColors.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,13 @@ extension FigmaExportCommand {
private func exportAndroidColors(colorPairs: [AssetPair<Color>], androidParams: Params.Android) throws {
let exporter = AndroidColorExporter(outputDirectory: androidParams.mainRes)
let files = exporter.export(colorPairs: colorPairs)

let lightColorsFileURL = androidParams.mainRes.appendingPathComponent("values/colors.xml")
let darkColorsFileURL = androidParams.mainRes.appendingPathComponent("values-night/colors.xml")

try? FileManager.default.removeItem(atPath: lightColorsFileURL.path)
try? FileManager.default.removeItem(atPath: darkColorsFileURL.path)

try fileWritter.write(files: files)
}
}
Expand Down
22 changes: 17 additions & 5 deletions Sources/FigmaExport/Subcommands/ExportIcons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ extension FigmaExportCommand {
}

private func exportiOSIcons(client: FigmaClient, params: Params, logger: Logger) throws {
guard let ios = params.ios else { return }
guard let ios = params.ios else {
logger.info("Nothing to do. You haven’t specified ios parameter in the config file.")
return
}

logger.info("Fetching icons info from Figma. Please wait...")
let loader = ImagesLoader(figmaClient: client, params: params, platform: .ios)
Expand Down Expand Up @@ -94,7 +97,10 @@ extension FigmaExportCommand {
}

private func exportAndroidIcons(client: FigmaClient, params: Params, logger: Logger) throws {
guard let android = params.android else { return }
guard let android = params.android, let androidIcons = android.icons else {
logger.info("Nothing to do. You haven’t specified android.icons parameter in the config file.")
return
}

// 1. Get Icons info
logger.info("Fetching icons info from Figma. Please wait...")
Expand Down Expand Up @@ -130,9 +136,15 @@ extension FigmaExportCommand {
logger.info("Converting SVGs to XMLs...")
try svgFileConverter.convert(inputDirectoryPath: tempDirectoryURL.path)

// Create output directory main/res/drawable/
let outputDirectory = URL(fileURLWithPath: android.mainRes.path)
.appendingPathComponent("drawable", isDirectory: true)
// Create output directory main/res/custom-directory/drawable/
let outputDirectory = URL(fileURLWithPath: android.mainRes
.appendingPathComponent(androidIcons.output)
.appendingPathComponent("drawable", isDirectory: true).path)

if filter == nil {
// Clear output directory
try? FileManager.default.removeItem(atPath: outputDirectory.path)
}

// 6. Move XML files to main/res/drawable/
localFiles = localFiles.map { fileContents -> FileContents in
Expand Down
53 changes: 41 additions & 12 deletions Sources/FigmaExport/Subcommands/ExportImages.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ extension FigmaExportCommand {
}

private func exportiOSImages(client: FigmaClient, params: Params, logger: Logger) throws {
guard let ios = params.ios else { return }
guard let ios = params.ios else {
logger.info("Nothing to do. You haven’t specified ios parameter in the config file.")
return
}

logger.info("Fetching images info from Figma. Please wait...")
let loader = ImagesLoader(figmaClient: client, params: params, platform: .ios)
Expand Down Expand Up @@ -93,7 +96,10 @@ extension FigmaExportCommand {
}

private func exportAndroidImages(client: FigmaClient, params: Params, logger: Logger) throws {
guard let android = params.android else { return }
guard let androidImages = params.android?.images else {
logger.info("Nothing to do. You haven’t specified android.images parameter in the config file.")
return
}

logger.info("Fetching images info from Figma. Please wait...")
let loader = ImagesLoader(figmaClient: client, params: params, platform: .android)
Expand All @@ -107,7 +113,7 @@ extension FigmaExportCommand {
)
let images = try processor.process(light: imagesTuple.light, dark: imagesTuple.dark).get()

switch android.images.format {
switch androidImages.format {
case .svg:
try exportAndroidSVGImages(images: images, params: params, logger: logger)
case .png, .webp:
Expand All @@ -118,7 +124,10 @@ extension FigmaExportCommand {
}

private func exportAndroidSVGImages(images: [AssetPair<ImagesProcessor.AssetType>], params: Params, logger: Logger) throws {
guard let android = params.android else { return }
guard let android = params.android, let androidImages = android.images else {
logger.info("Nothing to do. You haven’t specified android.images parameter in the config file.")
return
}

// Create empty temp directory
let tempDirectoryLightURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
Expand Down Expand Up @@ -155,12 +164,22 @@ extension FigmaExportCommand {
}

logger.info("Writting files to Android Studio project...")

// Create output directory main/res/drawable/
let lightDirectory = URL(fileURLWithPath: android.mainRes.path)
.appendingPathComponent("drawable", isDirectory: true)

let darkDirectory = URL(fileURLWithPath: android.mainRes.path)
.appendingPathComponent("drawable-night", isDirectory: true)
let lightDirectory = URL(fileURLWithPath: android.mainRes
.appendingPathComponent(androidImages.output)
.appendingPathComponent("drawable", isDirectory: true).path)

let darkDirectory = URL(fileURLWithPath: android.mainRes
.appendingPathComponent(androidImages.output)
.appendingPathComponent("drawable-night", isDirectory: true).path)

if filter == nil {
// Clear output directory
try? FileManager.default.removeItem(atPath: lightDirectory.path)
try? FileManager.default.removeItem(atPath: darkDirectory.path)
}

// Move XML files to main/res/drawable/
localFiles = localFiles.map { fileContents -> FileContents in
Expand All @@ -187,7 +206,10 @@ extension FigmaExportCommand {
}

private func exportAndroidRasterImages(images: [AssetPair<ImagesProcessor.AssetType>], params: Params, logger: Logger) throws {
guard let android = params.android else { return }
guard let android = params.android, let androidImages = android.images else {
logger.info("Nothing to do. You haven’t specified android.images parameter in the config file.")
return
}

// Create empty temp directory
let tempDirectoryURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString)
Expand All @@ -210,7 +232,7 @@ extension FigmaExportCommand {
try fileWritter.write(files: localFiles)

// Convert to WebP
if android.images.format == .webp, let options = android.images.webpOptions {
if androidImages.format == .webp, let options = androidImages.webpOptions {
logger.info("Converting PNG files to WebP...")
let converter: WebpConverter
switch (options.encoding, options.quality) {
Expand All @@ -226,13 +248,20 @@ extension FigmaExportCommand {
return file.changingExtension(newExtension: "webp")
}
}

if filter == nil {
// Clear output directory
let outputDirectory = URL(fileURLWithPath: android.mainRes.appendingPathComponent(androidImages.output).path)
try? FileManager.default.removeItem(atPath: outputDirectory.path)
}

logger.info("Writting files to Android Studio project...")

// Move PNG/WebP files to main/res/drawable-XXXdpi/
// Move PNG/WebP files to main/res/figma-export-images/drawable-XXXdpi/
localFiles = localFiles.map { fileContents -> FileContents in
let directoryName = Drawable.scaleToDrawableName(fileContents.scale, dark: fileContents.dark)
let directory = URL(fileURLWithPath: android.mainRes.path).appendingPathComponent(directoryName, isDirectory: true)
let directory = URL(fileURLWithPath: android.mainRes.appendingPathComponent(androidImages.output).path)
.appendingPathComponent(directoryName, isDirectory: true)
return FileContents(
destination: Destination(directory: directory, file: fileContents.destination.file),
dataFile: fileContents.destination.url
Expand Down

0 comments on commit a68f506

Please sign in to comment.