Skip to content

Commit

Permalink
Reformat code and resolve manual linter complaints (#38)
Browse files Browse the repository at this point in the history
Signed-off-by: Henrik Panhans <[email protected]>
  • Loading branch information
henrik-dmg authored Oct 30, 2024
1 parent 5fc94d8 commit 604b02a
Show file tree
Hide file tree
Showing 48 changed files with 363 additions and 221 deletions.
6 changes: 3 additions & 3 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,17 @@ let package = Package(
],
dependencies: [
.package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"),
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0")
.package(url: "https://github.com/jpsim/Yams.git", from: "5.0.0"),
],
targets: [
.executableTarget(
name: "SwiftFrame",
dependencies: [
"SwiftFrameCore",
.product(name: "ArgumentParser", package: "swift-argument-parser")
.product(name: "ArgumentParser", package: "swift-argument-parser"),
]
),
.target(name: "SwiftFrameCore", dependencies: ["Yams"]),
.testTarget(name: "SwiftFrameTests", dependencies: ["SwiftFrameCore"])
.testTarget(name: "SwiftFrameTests", dependencies: ["SwiftFrameCore"]),
]
)
3 changes: 2 additions & 1 deletion Sources/SwiftFrame/Render.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ struct Render: ParsableCommand {

@Flag(
name: .long,
help: "Outputs the whole image canvas into the output directories before slicing it up into the correct screenshot sizes. Helpful for troubleshooting"
help:
"Outputs the whole image canvas into the output directories before slicing it up into the correct screenshot sizes. Helpful for troubleshooting"
)
var outputWholeImage = false

Expand Down
28 changes: 18 additions & 10 deletions Sources/SwiftFrame/Scaffold.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ struct Scaffold: ParsableCommand, VerbosePrintable {

@Flag
var noHelperFiles = false

@Flag
var verbose = false

Expand All @@ -43,7 +43,7 @@ struct Scaffold: ParsableCommand, VerbosePrintable {
templatesDirectoryURL,
]

try directoriesToCreate.forEach { directory in
for directory in directoriesToCreate {
printVerbose("Creating directory \(directory.path)")
numberOfCreatedDirectories += 1
try FileManager.default.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
Expand All @@ -56,7 +56,7 @@ struct Scaffold: ParsableCommand, VerbosePrintable {
numberOfCreatedFiles += 1
}

try locales.forEach { locale in
for locale in locales {
if shouldCreateHelperFiles {
let localeStringsFileContents = "\"some string key\" = \"the corresponding translation\";"
let localeStringsFileURL = stringsDirectoryURL.appendingPathComponent("\(locale).strings")
Expand All @@ -65,17 +65,25 @@ struct Scaffold: ParsableCommand, VerbosePrintable {
numberOfCreatedFiles += 1
}

try Scaffold.defaultDevices.forEach { deviceName in
for deviceName in Scaffold.defaultDevices {
printVerbose("Creating screenshot directory for locale \(locale) and device \(deviceName)")
numberOfCreatedDirectories += 1

let localeScreenshotDirectoryURL = screenshotsDirectoryURL.appendingPathComponent(deviceName).appendingPathComponent(locale)
try FileManager.default.createDirectory(at: localeScreenshotDirectoryURL, withIntermediateDirectories: true, attributes: nil)

try FileManager.default.createDirectory(
at: localeScreenshotDirectoryURL,
withIntermediateDirectories: true,
attributes: nil
)

if shouldCreateHelperFiles {
let markdownContents = "# \(deviceName) - \(locale)\n\nPlace your screenshots for \(deviceName) (\(locale)) in this folder\n" +
"Please make sure that all screenshots that represent the same screen have the same name for every locale."
try FileManager.default.ky_writeToFile(markdownContents, destination: localeScreenshotDirectoryURL.appendingPathComponent("README.md"))
let markdownContents =
"# \(deviceName) - \(locale)\n\nPlace your screenshots for \(deviceName) (\(locale)) in this folder\n"
+ "Please make sure that all screenshots that represent the same screen have the same name for every locale."
try FileManager.default.ky_writeToFile(
markdownContents,
destination: localeScreenshotDirectoryURL.appendingPathComponent("README.md")
)
numberOfCreatedFiles += 1
}
}
Expand Down
55 changes: 33 additions & 22 deletions Sources/SwiftFrameCore/Config/ConfigData.swift
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import Foundation
import AppKit
import Foundation

protocol ConfigValidateable {
func validate() throws
func printSummary(insetByTabs tabs: Int)
}

/// First key is locale, second is regular key in string file
/// First key is locale, second is regular key in string file.
typealias LocalizedStringFiles = [String: [String: String]]

struct ConfigData: Decodable, ConfigValidateable {
Expand Down Expand Up @@ -51,8 +51,8 @@ struct ConfigData: Decodable, ConfigValidateable {
textColorSource: ColorSource,
outputFormat: FileFormat,
deviceData: [DeviceData],
localesRegex: String? = nil)
{
localesRegex: String? = nil
) {
self.textGroups = textGroups
self.stringsPath = stringsPath
self.maxFontSize = maxFontSize
Expand All @@ -67,15 +67,18 @@ struct ConfigData: Decodable, ConfigValidateable {
// MARK: - Processing

mutating func process() throws {
let regex: Regex<AnyRegexOutput>? = if let localesRegex, !localesRegex.isEmpty {
try Regex(localesRegex)
} else {
nil
}
let regex: Regex<AnyRegexOutput>? =
if let localesRegex, !localesRegex.isEmpty {
try Regex(localesRegex)
} else {
nil
}

deviceData = try deviceData.map { try $0.makeProcessedData(localesRegex: regex) }

let textFiles = try FileManager.default.ky_filesAtPath(stringsPath.absoluteURL, with: "strings").filterByFileOrFoldername(regex: regex)
let textFiles = try FileManager.default.ky_filesAtPath(stringsPath.absoluteURL, with: "strings").filterByFileOrFoldername(
regex: regex
)
let strings = textFiles.compactMap { NSDictionary(contentsOf: $0) as? [String: String] }
titles = Dictionary(uniqueKeysWithValues: zip(textFiles.map({ $0.fileName }), strings))
}
Expand All @@ -86,16 +89,20 @@ struct ConfigData: Decodable, ConfigValidateable {
guard !deviceData.isEmpty else {
throw NSError(
description: "No screenshot data was supplied",
expectation: "Please supply at least one screenshot along with metadata")
expectation: "Please supply at least one screenshot along with metadata"
)
}

guard !outputPaths.isEmpty else {
throw NSError(
description: "No output paths were specified",
expectation: "Please specify at least one output directory")
expectation: "Please specify at least one output directory"
)
}

try deviceData.forEach { try $0.validate() }
for device in deviceData {
try device.validate()
}
}

func printSummary(insetByTabs tabs: Int) {
Expand All @@ -106,21 +113,24 @@ struct ConfigData: Decodable, ConfigValidateable {
CommandLineFormatter.printKeyValue(
"String Files",
value: titles.isEmpty ? "none" : titles.keys.joined(separator: ", "),
insetBy: tabs)
insetBy: tabs
)

ky_print("Output paths:", insetByTabs: tabs)
outputPaths.forEach { ky_print($0.path.formattedGreen(), insetByTabs: tabs + 1) }
for path in outputPaths {
ky_print(path.path.formattedGreen(), insetByTabs: tabs + 1)
}

ky_print("Device data:", insetByTabs: tabs)
deviceData.forEach {
$0.printSummary(insetByTabs: tabs + 1)
for device in deviceData {
device.printSummary(insetByTabs: tabs + 1)
print()
}

if !textGroups.isEmpty {
print("Text groups:")
textGroups.forEach {
$0.printSummary(insetByTabs: tabs + 1)
for textGroup in textGroups {
textGroup.printSummary(insetByTabs: tabs + 1)
print()
}
} else {
Expand All @@ -133,7 +143,7 @@ struct ConfigData: Decodable, ConfigValidateable {
// MARK: - Screenshot Factory

func makeAssociatedStrings(for device: DeviceData, locale: String) throws -> [AssociatedString] {
return try device.textData.map {
try device.textData.map {
guard let title = titles[locale]?[$0.titleIdentifier] else {
throw NSError(description: "Title with key \"\($0.titleIdentifier)\" not found in string file \"\(locale)\"")
}
Expand All @@ -142,12 +152,13 @@ struct ConfigData: Decodable, ConfigValidateable {
}

func makeSharedFontSizes(for associatedStrings: [AssociatedString]) throws -> [String: CGFloat] {
return try textGroups.reduce(into: [String: CGFloat]()) { dictionary, group in
try textGroups.reduce(into: [String: CGFloat]()) { dictionary, group in
let strings = associatedStrings.filter({ $0.data.groupIdentifier == group.identifier })
dictionary[group.identifier] = try group.sharedFontSize(
with: strings,
globalFont: try fontSource.font(),
globalMaxSize: maxFontSize)
globalMaxSize: maxFontSize
)
}
}

Expand Down
41 changes: 21 additions & 20 deletions Sources/SwiftFrameCore/Config/DeviceData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ struct DeviceData: Decodable, ConfigValidateable {

private(set) var screenshotsGroupedByLocale: [String: [String: URL]]!
private(set) var templateImage: NSBitmapImageRep?
private(set) var screenshotData = [ScreenshotData]()
private(set) var textData = [TextData]()
private(set) var screenshotData: [ScreenshotData] = []
private(set) var textData: [TextData] = []

// MARK: - Coding Keys

Expand All @@ -40,10 +40,10 @@ struct DeviceData: Decodable, ConfigValidateable {
numberOfSlices: Int,
screenshotsGroupedByLocale: [String: [String: URL]]? = nil,
templateImage: NSBitmapImageRep? = nil,
screenshotData: [ScreenshotData] = [ScreenshotData](),
textData: [TextData] = [TextData](),
gapWidth: Int = 0)
{
screenshotData: [ScreenshotData] = [],
textData: [TextData] = [],
gapWidth: Int = 0
) {
self.outputSuffixes = outputSuffixes
self.templateImagePath = templateImagePath
self.screenshotsPath = screenshotsPath
Expand All @@ -57,24 +57,27 @@ struct DeviceData: Decodable, ConfigValidateable {

// MARK: - Methods

// swift-format:
func makeProcessedData(localesRegex: Regex<AnyRegexOutput>?) throws -> DeviceData {
guard let templateImage = ImageLoader.loadRepresentation(at: templateImagePath.absoluteURL) else {
throw NSError(description: "Error while loading template image at path \(templateImagePath.absoluteString)")
}

var parsedScreenshots = [String: [String: URL]]()
try screenshotsPath.absoluteURL.subDirectories.filterByFileOrFoldername(regex: localesRegex).forEach { folder in
var dictionary = [String: URL]()
var parsedScreenshots: [String: [String: URL]] = [:]
for folder in try screenshotsPath.absoluteURL.subDirectories.filterByFileOrFoldername(regex: localesRegex) {
var dictionary: [String: URL] = [:]
// swift-format-ignore: ReplaceForEachWithForLoop
try FileManager.default.contentsOfDirectory(at: folder, includingPropertiesForKeys: nil, options: [.skipsHiddenFiles])
.filter { url in
kScreenshotExtensions.contains(url.pathExtension.lowercased())
&& screenshotData.contains(where: { $0.screenshotName == url.lastPathComponent })
&& screenshotData.contains(where: { $0.screenshotName == url.lastPathComponent })
}.forEach { dictionary[$0.lastPathComponent] = $0 }
parsedScreenshots[folder.lastPathComponent] = dictionary
}

let processedTextData = try textData.map { try $0.makeProcessedData(size: templateImage.size) }
let processedScreenshotData = screenshotData
let processedScreenshotData =
screenshotData
.map { $0.makeProcessedData(size: templateImage.size) }
.sorted { $0.zIndex < $1.zIndex }

Expand Down Expand Up @@ -122,15 +125,13 @@ struct DeviceData: Decodable, ConfigValidateable {
)
}

try screenshotData.forEach { try $0.validate() }
try textData.forEach { try $0.validate() }
for screenshot in screenshotData { try screenshot.validate() }
for text in textData { try text.validate() }

let screenshotNames = screenshotData.map { $0.screenshotName }
try screenshotsGroupedByLocale.forEach { localeDict in
try screenshotNames.forEach { name in
if localeDict.value[name] == nil {
throw NSError(description: "Screenshot folder \(localeDict.key) does not contain a screenshot named \"\(name)\"")
}
for localeDict in screenshotsGroupedByLocale {
for name in screenshotNames where localeDict.value[name] == nil {
throw NSError(description: "Screenshot folder \(localeDict.key) does not contain a screenshot named \"\(name)\"")
}
}
}
Expand All @@ -156,8 +157,8 @@ struct DeviceData: Decodable, ConfigValidateable {
insetBy: tabs
)

screenshotData.forEach { $0.printSummary(insetByTabs: tabs) }
textData.forEach { $0.printSummary(insetByTabs: tabs) }
for screenshot in screenshotData { screenshot.printSummary(insetByTabs: tabs) }
for text in textData { text.printSummary(insetByTabs: tabs) }
}

}
3 changes: 2 additions & 1 deletion Sources/SwiftFrameCore/Config/ScreenshotData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ struct ScreenshotData: Decodable, ConfigValidateable, Equatable {
bottomRight: bottomRight.convertingToBottomLeftOrigin(withSize: size),
topLeft: topLeft.convertingToBottomLeftOrigin(withSize: size),
topRight: topRight.convertingToBottomLeftOrigin(withSize: size),
zIndex: zIndex)
zIndex: zIndex
)
}

// MARK: - ConfigValidateable
Expand Down
7 changes: 4 additions & 3 deletions Sources/SwiftFrameCore/Config/TextData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@ struct TextData: Decodable, ConfigValidateable {
groupIdentifier: String?,
topLeft: Point,
bottomRight: Point,
textColorOverride: NSColor? = nil)
{
textColorOverride: NSColor? = nil
) {
self.titleIdentifier = titleIdentifier
self.textAlignment = textAlignment
self.maxFontSizeOverride = maxFontSizeOverride
Expand Down Expand Up @@ -77,7 +77,8 @@ struct TextData: Decodable, ConfigValidateable {
groupIdentifier: groupIdentifier,
topLeft: processedTopLeft,
bottomRight: processedBottomRight,
textColorOverride: colorOverride)
textColorOverride: colorOverride
)
}

// MARK: - ConfigValidateable
Expand Down
6 changes: 4 additions & 2 deletions Sources/SwiftFrameCore/Config/TextGroup.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ struct TextGroup: Decodable, ConfigValidateable, Hashable {

func sharedFontSize(with strings: [AssociatedString], globalFont: NSFont, globalMaxSize: CGFloat) throws -> CGFloat {
let maxFontSizes: [CGFloat] = try strings.compactMap {
return try TextRenderer.maximumFontSizeThatFits(
try TextRenderer.maximumFontSizeThatFits(
string: $0.string,
font: $0.data.fontOverride?.font() ?? globalFont,
alignment: $0.data.textAlignment,
maxSize: $0.data.maxFontSizeOverride ?? globalMaxSize,
size: $0.data.rect.size)
size: $0.data.rect.size
)
}
// Can force-unwrap since array will never be empty
// swift-format-ignore: NeverForceUnwrap
return ([globalMaxSize, maxFontSize] + maxFontSizes).min()!
}
}
10 changes: 5 additions & 5 deletions Sources/SwiftFrameCore/Extensions/FileManager+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ extension FileManager {
}

func ky_clearDirectories(_ urls: [FileURL], localeFolders: [String]) throws {
try urls.forEach { url in
for url in urls {
let mappedURLs: [URL] = localeFolders.compactMap {
let mappedURL = url.absoluteURL.appendingPathComponent($0)
return fileExists(atPath: mappedURL.path) ? mappedURL : nil
}
try mappedURLs.forEach {
try removeItem(at: $0)
for url in mappedURLs {
try removeItem(at: url)
}
}
}
Expand All @@ -33,11 +33,11 @@ extension FileManager {
try ky_createFile(atURL: destination, contents: data, attributes: nil)
}

public func ky_createFile(atURL url: URL, contents: Data?, attributes: [FileAttributeKey : Any]? = nil) throws {
public func ky_createFile(atURL url: URL, contents: Data?, attributes: [FileAttributeKey: Any]? = nil) throws {
try ky_createFile(atPath: url.path, contents: contents, attributes: attributes)
}

public func ky_createFile(atPath path: String, contents: Data?, attributes: [FileAttributeKey : Any]? = nil) throws {
public func ky_createFile(atPath path: String, contents: Data?, attributes: [FileAttributeKey: Any]? = nil) throws {
if !createFile(atPath: path, contents: contents, attributes: attributes) {
throw NSError(description: "Could not create file at path \(path)")
}
Expand Down
Loading

0 comments on commit 604b02a

Please sign in to comment.