polyhorn_cli/ios/tasks/
generate_xcassets.rs

1use super::{IOSContext, IOSError};
2use crate::core::{rasterize, Manager, Task};
3use crate::ios::xcassets::{Folder, Image, ImageSet, Info, Properties, XcAssets};
4
5/// This task generates an Xcode-compatible assets catalog for the assets of
6/// the Polyhorn project that is being compiled and its dependencies.
7pub struct GenerateXcassets;
8
9impl Task for GenerateXcassets {
10    type Context = IOSContext;
11    type Error = IOSError;
12
13    fn verb(&self) -> &str {
14        "Generating"
15    }
16
17    fn message(&self) -> &str {
18        "xcassets"
19    }
20
21    fn detail(&self) -> &str {
22        "for iOS"
23    }
24
25    fn run(
26        &self,
27        context: Self::Context,
28        _manager: &mut Manager,
29    ) -> Result<Self::Context, Self::Error> {
30        let target_dir = context.config.target_dir.join("polyhorn-ios");
31
32        let mut cmd = cargo_metadata::MetadataCommand::new();
33        cmd.manifest_path(context.config.manifest_dir.join("Cargo.toml"));
34        let metadata = cmd.exec().unwrap();
35
36        let mut result_path = std::env::current_dir().unwrap();
37        result_path.push(target_dir.join("Sources/Assets.xcassets/"));
38        let _ = std::fs::create_dir_all(&result_path);
39
40        {
41            let mut result_path = result_path.clone();
42            result_path.push("Contents.json");
43
44            serde_json::to_writer_pretty(
45                std::fs::File::create(result_path).unwrap(),
46                &XcAssets {
47                    info: Info {
48                        author: "polyhorn",
49                        version: 1,
50                    },
51                },
52            )
53            .unwrap();
54        }
55
56        {
57            let mut result_path = result_path.clone();
58            result_path.push("AppIcon.appiconset");
59            let _ = std::fs::create_dir_all(&result_path);
60
61            result_path.push("Contents.json");
62
63            serde_json::to_writer_pretty(
64                std::fs::File::create(result_path).unwrap(),
65                &ImageSet {
66                    images: vec![
67                        Image {
68                            filename: None,
69                            idiom: "iphone",
70                            scale: "2x",
71                            size: Some("20x20"),
72                        },
73                        Image {
74                            filename: None,
75                            idiom: "iphone",
76                            scale: "3x",
77                            size: Some("20x20"),
78                        },
79                        Image {
80                            filename: None,
81                            idiom: "iphone",
82                            scale: "2x",
83                            size: Some("29x29"),
84                        },
85                        Image {
86                            filename: None,
87                            idiom: "iphone",
88                            scale: "3x",
89                            size: Some("29x29"),
90                        },
91                        Image {
92                            filename: None,
93                            idiom: "iphone",
94                            scale: "2x",
95                            size: Some("40x40"),
96                        },
97                        Image {
98                            filename: None,
99                            idiom: "iphone",
100                            scale: "3x",
101                            size: Some("40x40"),
102                        },
103                        Image {
104                            filename: None,
105                            idiom: "iphone",
106                            scale: "2x",
107                            size: Some("60x60"),
108                        },
109                        Image {
110                            filename: None,
111                            idiom: "iphone",
112                            scale: "3x",
113                            size: Some("60x60"),
114                        },
115                        Image {
116                            filename: None,
117                            idiom: "ipad",
118                            scale: "1x",
119                            size: Some("20x20"),
120                        },
121                        Image {
122                            filename: None,
123                            idiom: "ipad",
124                            scale: "2x",
125                            size: Some("20x20"),
126                        },
127                        Image {
128                            filename: None,
129                            idiom: "ipad",
130                            scale: "1x",
131                            size: Some("29x29"),
132                        },
133                        Image {
134                            filename: None,
135                            idiom: "ipad",
136                            scale: "2x",
137                            size: Some("29x29"),
138                        },
139                        Image {
140                            filename: None,
141                            idiom: "ipad",
142                            scale: "1x",
143                            size: Some("40x40"),
144                        },
145                        Image {
146                            filename: None,
147                            idiom: "ipad",
148                            scale: "2x",
149                            size: Some("40x40"),
150                        },
151                        Image {
152                            filename: None,
153                            idiom: "ipad",
154                            scale: "1x",
155                            size: Some("76x76"),
156                        },
157                        Image {
158                            filename: None,
159                            idiom: "ipad",
160                            scale: "2x",
161                            size: Some("76x76"),
162                        },
163                        Image {
164                            filename: None,
165                            idiom: "ipad",
166                            scale: "2x",
167                            size: Some("83.5x83.5"),
168                        },
169                        Image {
170                            filename: None,
171                            idiom: "ios-marketing",
172                            scale: "1x",
173                            size: Some("1024x1024"),
174                        },
175                    ],
176                    info: Info {
177                        author: "polyhorn",
178                        version: 1,
179                    },
180                },
181            )
182            .unwrap();
183        }
184
185        for package in metadata.packages {
186            let mut path = package.manifest_path.clone();
187            path.pop();
188            path.push("Polyhorn.toml");
189
190            if !path.exists() {
191                continue;
192            }
193
194            path.pop();
195            path.push("assets");
196
197            for entry in std::fs::read_dir(path).unwrap() {
198                if let Ok(entry) = entry {
199                    if entry
200                        .path()
201                        .extension()
202                        .map(|ext| ext == "svg")
203                        .unwrap_or_default()
204                    {
205                        let path = entry.path();
206                        let name = path.file_stem().unwrap().to_str().unwrap();
207
208                        let mut result_path = std::env::current_dir().unwrap();
209                        result_path.push(target_dir.join("Sources/Assets.xcassets/"));
210                        result_path.push(&package.name);
211                        let _ = std::fs::create_dir_all(&result_path);
212
213                        {
214                            let mut result_path = result_path.clone();
215                            result_path.push("Contents.json");
216
217                            serde_json::to_writer_pretty(
218                                std::fs::File::create(result_path).unwrap(),
219                                &Folder {
220                                    info: Info {
221                                        author: "polyhorn",
222                                        version: 1,
223                                    },
224                                    properties: Properties {
225                                        provides_namespace: true,
226                                    },
227                                },
228                            )
229                            .unwrap();
230                        }
231
232                        result_path.push(name.to_owned() + ".imageset");
233                        let _ = std::fs::create_dir_all(&result_path);
234
235                        let zooms = [("1x", 1.0), ("2x", 2.0), ("3x", 3.0)];
236
237                        for &(suffix, zoom) in &zooms {
238                            let mut result_path = result_path.clone();
239                            result_path.push("image".to_owned() + "@" + suffix + ".png");
240
241                            rasterize(&entry.path(), zoom, &result_path).unwrap();
242                        }
243
244                        result_path.push("Contents.json");
245
246                        serde_json::to_writer_pretty(
247                            std::fs::File::create(result_path).unwrap(),
248                            &ImageSet {
249                                images: vec![
250                                    Image {
251                                        filename: Some("image@1x.png"),
252                                        idiom: "universal",
253                                        scale: "1x",
254                                        size: None,
255                                    },
256                                    Image {
257                                        filename: Some("image@2x.png"),
258                                        idiom: "universal",
259                                        scale: "2x",
260                                        size: None,
261                                    },
262                                    Image {
263                                        filename: Some("image@3x.png"),
264                                        idiom: "universal",
265                                        scale: "3x",
266                                        size: None,
267                                    },
268                                ],
269                                info: Info {
270                                    author: "polyhorn",
271                                    version: 1,
272                                },
273                            },
274                        )
275                        .unwrap();
276                    }
277                }
278            }
279        }
280
281        Ok(context)
282    }
283}