-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathXCrafter.py
executable file
·148 lines (119 loc) · 5.67 KB
/
XCrafter.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#!/usr/bin/python
import os
import json
import argparse
import shutil
import re
def to_snake_case(name):
name = re.sub(r'[\s\-]+', '_', name)
name = re.sub(r'(?<!^)(?=[A-Z])', '_', name).lower()
name = re.sub(r'_+', '_', name) # Replace multiple underscores with a single underscore
return name
def to_camel_case(snake_str):
components = snake_str.split('_')
return components[0] + ''.join(x.title() for x in components[1:])
def create_xcassets(asset_name, images_folder, output_folder=None, subfolder_name=None, enum_class_name=None):
# Define the default output path on the desktop if not provided
if output_folder is None:
desktop_path = os.path.join(os.path.expanduser("~"), "Desktop")
output_folder = os.path.join(desktop_path, asset_name)
print(f"No output folder specified. Using default: {output_folder}")
# Create the output directory if it doesn't exist
os.makedirs(output_folder, exist_ok=True)
# Define the output paths
xcassets_path = os.path.join(output_folder, asset_name + ".xcassets")
os.makedirs(xcassets_path, exist_ok=True)
# Optionally create a subfolder inside .xcassets
if subfolder_name:
xcassets_path = os.path.join(xcassets_path, subfolder_name)
os.makedirs(xcassets_path, exist_ok=True)
# List all images in the specified folder and filter out non-image files
images = [f for f in os.listdir(images_folder) if f.endswith(('.png', '.svg')) and os.path.isfile(os.path.join(images_folder, f))]
# Group images by their base name (without @2x, @3x, etc.)
image_groups = {}
for image in images:
base_name = re.sub(r'(@[23]x)?(\.png|\.svg)$', '', image)
if base_name not in image_groups:
image_groups[base_name] = []
image_groups[base_name].append(image)
# Process each group of images
icon_cases = []
for base_name, image_group in image_groups.items():
snake_case_base_name = to_snake_case(base_name)
camel_case_name = to_camel_case(snake_case_base_name)
asset_folder_path = os.path.join(xcassets_path, snake_case_base_name + ".imageset")
os.makedirs(asset_folder_path, exist_ok=True)
contents_json_path = os.path.join(asset_folder_path, "Contents.json")
# Prepare the image entries for Contents.json
images_json = []
for image in image_group:
snake_case_image = to_snake_case(os.path.splitext(image)[0]) + os.path.splitext(image)[1].lower()
if image.endswith('.svg'):
image_entry = {
"filename": snake_case_image,
"idiom": "universal"
}
else:
if '@2x' in image:
scale = '2x'
elif '@3x' in image:
scale = '3x'
else:
scale = '1x' # default scale for png
image_entry = {
"filename": snake_case_image,
"idiom": "universal",
"scale": scale
}
images_json.append(image_entry)
# Copy and rename images to the .xcassets folder
shutil.copy(os.path.join(images_folder, image), os.path.join(asset_folder_path, snake_case_image))
# Define the Contents.json structure
contents_json = {
"images": images_json,
"info": {
"version": 1,
"author": "xcode"
}
}
# Write the Contents.json file
with open(contents_json_path, 'w') as json_file:
json.dump(contents_json, json_file, indent=4)
# Add to the enum cases
icon_cases.append(f'case {camel_case_name} = "{snake_case_base_name}"')
print(f".xcassets folder created at: {os.path.abspath(xcassets_path)}")
# Generate the Swift Enum if class name is provided
if enum_class_name:
generate_swift_enum(enum_class_name, icon_cases, output_folder)
def generate_swift_enum(enum_class_name, cases, output_folder):
enum_template = """
import UIKit
public enum %s: String, CaseIterable {
%s
static var allIcons: [%s] {
return %s.allCases
}
var iconName: String {
return rawValue
}
}
"""
enum_cases = "\n".join([f" {case}" for case in cases])
enum_content = enum_template % (enum_class_name, enum_cases, enum_class_name, enum_class_name)
swift_file_path = os.path.join(output_folder, f"{enum_class_name}.swift")
with open(swift_file_path, 'w') as swift_file:
swift_file.write(enum_content)
print(f"{enum_class_name}.swift file created at: {swift_file_path}")
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Create .xcassets folder structure for an Xcode project",
epilog="Example usage:\n python create_xcassets.py -n MyIcon -i /path/to/images_folder -o /path/to/output_folder -s SubfolderName --enum Icons",
formatter_class=argparse.RawTextHelpFormatter
)
parser.add_argument("-n", "--name", required=True, help="The name of the asset to create (will be converted to snake case)")
parser.add_argument("-i", "--images_folder", required=True, help="The folder containing the images")
parser.add_argument("-o", "--output_folder", help="The output folder to save the .xcassets and Swift enum")
parser.add_argument("-s", "--subfolder", help="The name of the subfolder to create inside the .xcassets folder")
parser.add_argument("--enum", help="The name of the Swift enum class to create")
args = parser.parse_args()
create_xcassets(args.name, args.images_folder, args.output_folder, args.subfolder, args.enum)