From 7184f92ddd45be56bd98e297969ace2572af23e9 Mon Sep 17 00:00:00 2001 From: Aleksei Kakoulin <36570774+alexey1312@users.noreply.github.com> Date: Thu, 21 Jul 2022 00:11:58 +0700 Subject: [PATCH] [Android] Support RTL (#182) * Update FileContents * Update FileDownloader * Update FileWriter * Update ExportIcons * Update README * Fix name * Update FileWriter * Update ExportIcons --- README.md | 4 +-- .../FigmaExport/Output/FileDownloader.swift | 3 +- Sources/FigmaExport/Output/FileWriter.swift | 6 ++++ .../FigmaExport/Subcommands/ExportIcons.swift | 31 ++++++++++++++++--- Sources/FigmaExportCore/FileContents.swift | 10 ++++-- 5 files changed, 44 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 7f122d5a..4f013bfd 100644 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ Table of Contents: * Supports High contrast colors for Xcode * Supports SwiftUI and UIKit * Supports Objective-C -* Supports RTL (only iOS) +* Supports RTL > Exporting icons and images works only for Professional/Organisation Figma plan because FigmaExport use *Shareable team libraries*. @@ -452,7 +452,7 @@ Custom Stencil templates must have the following names: If a color, icon or image is unique for iOS or Android platform, it should contains "ios" or "android" word in the description field in the properties. If a color, icon or image is used only by the designer, and it should not be exported, the word "none" should be specified in the description field. -If an icon supports RTL (iOS only), it should contains "rtl" word in the description field in the properties. +If an icon supports RTL, it should contains "rtl" word in the description field in the properties. **Styles and Components must be published to a Team Library.** diff --git a/Sources/FigmaExport/Output/FileDownloader.swift b/Sources/FigmaExport/Output/FileDownloader.swift index 07827042..c3d63926 100644 --- a/Sources/FigmaExport/Output/FileDownloader.swift +++ b/Sources/FigmaExport/Output/FileDownloader.swift @@ -42,7 +42,8 @@ final class FileDownloader { destination: file.destination, dataFile: fileURL, scale: file.scale, - dark: file.dark + dark: file.dark, + isRTL: file.isRTL ) newFiles.append(newFile) downloaded += 1 diff --git a/Sources/FigmaExport/Output/FileWriter.swift b/Sources/FigmaExport/Output/FileWriter.swift index 5ebe8aa1..57187542 100644 --- a/Sources/FigmaExport/Output/FileWriter.swift +++ b/Sources/FigmaExport/Output/FileWriter.swift @@ -24,4 +24,10 @@ final class FileWriter { } } } + + func write(xmlFile: XMLDocument, directory: URL) throws { + let fileURL = URL(fileURLWithPath: directory.path) + let options: XMLNode.Options = [.nodePrettyPrint, .nodeCompactEmptyElement] + try xmlFile.xmlData(options: options).write(to: fileURL, options: .atomic) + } } diff --git a/Sources/FigmaExport/Subcommands/ExportIcons.swift b/Sources/FigmaExport/Subcommands/ExportIcons.swift index 17570a87..d59a0c3d 100644 --- a/Sources/FigmaExport/Subcommands/ExportIcons.swift +++ b/Sources/FigmaExport/Subcommands/ExportIcons.swift @@ -144,12 +144,12 @@ extension FigmaExportCommand { let lightFiles = asset.light.images.map { image -> FileContents in let fileURL = URL(string: "\(image.name).svg")! let dest = Destination(directory: tempDirectoryLightURL, file: fileURL) - return FileContents(destination: dest, sourceURL: image.url) + return FileContents(destination: dest, sourceURL: image.url, isRTL: image.isRTL) } let darkFiles = asset.dark?.images.map { image -> FileContents in let fileURL = URL(string: "\(image.name).svg")! let dest = Destination(directory: tempDirectoryDarkURL, file: fileURL) - return FileContents(destination: dest, sourceURL: image.url, dark: true) + return FileContents(destination: dest, sourceURL: image.url, dark: true, isRTL: image.isRTL) } ?? [] return lightFiles + darkFiles } @@ -182,6 +182,7 @@ extension FigmaExportCommand { // 6. Move XML files to main/res/drawable/ localFiles = localFiles.map { fileContents -> FileContents in + let directory = fileContents.dark ? darkDirectory : lightDirectory let source = fileContents.destination.url .deletingPathExtension() @@ -190,8 +191,9 @@ extension FigmaExportCommand { let fileURL = fileContents.destination.file .deletingPathExtension() .appendingPathExtension("xml") - - let directory = fileContents.dark ? darkDirectory : lightDirectory + + rewriteXMLFile(from: source, fileContents: fileContents) + return FileContents( destination: Destination(directory: directory, file: fileURL), dataFile: source @@ -227,3 +229,24 @@ extension FigmaExportCommand { } } } + +private extension FigmaExportCommand.ExportIcons { + private func rewriteXMLFile(from source: URL, fileContents: FileContents) { + guard fileContents.isRTL, + let attribute = XMLNode.attribute(withName: "android:autoMirrored", stringValue: "\(fileContents.isRTL)") as? XMLNode + else { return } + if let sourceXML = try? XMLDocument(contentsOf: source, options: .documentTidyXML) { + try? sourceXML.nodes(forXPath: "//vector").forEach { node in + guard let element = node as? XMLElement else { return } + element.addAttribute(attribute) + } + + do { + FigmaExportCommand.logger.info("Add autoMirrored property for xml file...") + try FigmaExportCommand.fileWriter.write(xmlFile: sourceXML, directory: source) + } catch { + FigmaExportCommand.logger.info("Rewrite XMLFile - \(sourceXML) is faild") + } + } + } +} diff --git a/Sources/FigmaExportCore/FileContents.swift b/Sources/FigmaExportCore/FileContents.swift index 86a18659..e0e94553 100644 --- a/Sources/FigmaExportCore/FileContents.swift +++ b/Sources/FigmaExportCore/FileContents.swift @@ -31,35 +31,39 @@ public struct FileContents: Equatable { public var dark: Bool = false public var scale: Double = 1.0 + public var isRTL: Bool = false /// In-memory file - public init(destination: Destination, data: Data, scale: Double = 1.0, dark: Bool = false) { + public init(destination: Destination, data: Data, scale: Double = 1.0, dark: Bool = false, isRTL: Bool = false) { self.destination = destination self.data = data self.dataFile = nil self.sourceURL = nil self.scale = scale self.dark = dark + self.isRTL = isRTL } /// Remote file - public init(destination: Destination, sourceURL: URL, scale: Double = 1.0, dark: Bool = false) { + public init(destination: Destination, sourceURL: URL, scale: Double = 1.0, dark: Bool = false, isRTL: Bool = false) { self.destination = destination self.data = nil self.dataFile = nil self.sourceURL = sourceURL self.scale = scale self.dark = dark + self.isRTL = isRTL } /// On-disk file - public init(destination: Destination, dataFile: URL, scale: Double = 1.0, dark: Bool = false) { + public init(destination: Destination, dataFile: URL, scale: Double = 1.0, dark: Bool = false, isRTL: Bool = false) { self.destination = destination self.data = nil self.dataFile = dataFile self.sourceURL = nil self.scale = scale self.dark = dark + self.isRTL = isRTL } /// Make a copy of the FileContents with different file extension