1use crate::domain::builder::spm_builder::*;
2use crate::utils::theme_colors::*;
3use iced::widget::{center_x, checkbox, column, text};
4use iced::{Color, Element};
5
6pub type AppElement<'a> = Element<'a, Message>;
7
8#[derive(Debug, Clone)]
9pub enum Message {
10 ChangelogToggled(bool),
11 ReadmeToggled(bool),
12 SwiftPackageIndexToggled(bool),
13 SwiftLintToggled(bool),
14 IosToggled(bool),
15 MacOsToggled(bool),
16 TvOsToggled(bool),
17 WatchOsToggled(bool),
18 VisionOsToggled(bool),
19 InputChanged(String),
20 GenerateSPM,
21}
22
23#[derive(Default)]
24pub struct SpmView {
25 changelog: bool,
26 readme: bool,
27 swift_package_index: bool,
28 swiftlint: bool,
29 ios: bool,
30 macos: bool,
31 tvos: bool,
32 watchos: bool,
33 visionos: bool,
34 input_content: String,
35 platform_error: bool,
36}
37
38pub fn run() -> iced::Result {
40 iced::application(SpmView::default, SpmView::update, SpmView::view).run()
41}
42
43impl SpmView {
44 pub fn update(&mut self, message: Message) {
46 match message {
47 Message::ChangelogToggled(val) => self.changelog = val,
48 Message::ReadmeToggled(val) => self.readme = val,
49 Message::SwiftPackageIndexToggled(val) => self.swift_package_index = val,
50 Message::SwiftLintToggled(val) => self.swiftlint = val,
51
52 Message::IosToggled(val) => {
53 if val {
54 self.ios = true;
55 self.macos = false;
56 self.tvos = false;
57 self.watchos = false;
58 self.visionos = false;
59 self.platform_error = false;
60 } else {
61 self.ios = false;
62 }
63 }
64 Message::MacOsToggled(val) => {
65 if val {
66 self.ios = false;
67 self.macos = true;
68 self.tvos = false;
69 self.watchos = false;
70 self.visionos = false;
71 self.platform_error = false;
72 } else {
73 self.macos = false;
74 }
75 }
76 Message::TvOsToggled(val) => {
77 if val {
78 self.ios = false;
79 self.macos = false;
80 self.tvos = true;
81 self.watchos = false;
82 self.visionos = false;
83 self.platform_error = false;
84 } else {
85 self.tvos = false;
86 }
87 }
88 Message::WatchOsToggled(val) => {
89 if val {
90 self.ios = false;
91 self.macos = false;
92 self.tvos = false;
93 self.watchos = true;
94 self.visionos = false;
95 self.platform_error = false;
96 } else {
97 self.watchos = false;
98 }
99 }
100 Message::VisionOsToggled(val) => {
101 if val {
102 self.ios = false;
103 self.macos = false;
104 self.tvos = false;
105 self.watchos = false;
106 self.visionos = true;
107 self.platform_error = false;
108 } else {
109 self.visionos = false;
110 }
111 }
112 Message::InputChanged(s) => self.input_content = s,
113 Message::GenerateSPM => {
114 let mut platforms = Vec::new();
115 if self.ios {
116 platforms.push("iOS");
117 }
118 if self.macos {
119 platforms.push("macOS");
120 }
121 if self.tvos {
122 platforms.push("tvOS");
123 }
124 if self.watchos {
125 platforms.push("watchOS");
126 }
127 if self.visionos {
128 platforms.push("visionOS");
129 }
130
131 if platforms.is_empty() {
132 self.platform_error = true;
133 return;
134 } else {
135 self.platform_error = false;
136 }
137
138 let mut project_name = self.input_content.clone();
139 if project_name.trim().is_empty() {
140 project_name = "Library".to_string();
141 }
142
143 let mut files = Vec::new();
144 if self.changelog {
145 files.push("Changelog");
146 }
147 if self.readme {
148 files.push("Readme");
149 }
150 if self.swift_package_index {
151 files.push("Swift Package Index");
152 }
153 if self.swiftlint {
154 files.push("SwiftLint");
155 }
156
157 tokio::spawn(async move {
158 if (SpmBuilder::builder(&project_name, files, platforms).await).is_ok() {
159 let command = format!("cd {} && open Package.swift", project_name);
160 let _ = std::process::Command::new("sh")
161 .arg("-c")
162 .arg(&command)
163 .spawn();
164 }
165 });
166 }
167 }
168 }
169
170 pub fn view(&self) -> AppElement<'_> {
172 column![
173 self.header_view(),
174 self.input_view(),
175 self.files_title_view(),
176 self.files_checkboxes_view(),
177 self.platforms_title_view(),
178 self.platforms_checkboxes_view(),
179 self.error_platform_view(),
180 self.generate_button_view(),
181 ]
182 .spacing(16)
183 .into()
184 }
185
186 fn header_view(&self) -> AppElement<'_> {
188 column![
189 center_x(
190 text("SPM Swift Package")
191 .color(ThemeColors::ORANGE)
192 .size(32)
193 )
194 .height(20),
195 center_x(
196 text(
197 "Command Line Tools for macOS to create Swift Package Manager projects with desirable files."
198 )
199 .color(ThemeColors::GRAY)
200 .size(14)
201 )
202 .padding(16),
203 ]
204 .spacing(16)
205 .into()
206 }
207
208 fn input_view(&self) -> AppElement<'_> {
210 iced::widget::Container::new(
211 iced::widget::text_input("Insert the name of the project", &self.input_content)
212 .on_input(Message::InputChanged)
213 .padding(8)
214 .size(18),
215 )
216 .padding([0, 24])
217 .into()
218 }
219
220 fn files_title_view(&self) -> AppElement<'_> {
222 let title = text("Choose the files you want to include in your project:")
223 .color(Color::WHITE)
224 .size(18);
225
226 iced::widget::Container::new(title).padding([0, 24]).into()
227 }
228
229 fn platforms_title_view(&self) -> AppElement<'_> {
231 let title = text("Choose the platforms you want to include in your project:")
232 .color(Color::WHITE)
233 .size(18);
234
235 iced::widget::Container::new(title).padding([0, 24]).into()
236 }
237
238 fn files_checkboxes_view(&self) -> AppElement<'_> {
240 let mut col = column![];
241
242 for checkbox in self.view_files_checkboxes() {
243 col = col.push(checkbox);
244 }
245
246 col.spacing(8).into()
247 }
248
249 fn platforms_checkboxes_view(&self) -> AppElement<'_> {
251 let mut col = column![];
252
253 for checkbox in self.view_platforms_checkboxes() {
254 col = col.push(checkbox);
255 }
256
257 col.spacing(8).into()
258 }
259
260 fn generate_button_view(&self) -> AppElement<'_> {
262 iced::widget::Container::new(
263 iced::widget::button(text("Generate SPM").size(16).color(Color::WHITE))
264 .on_press(Message::GenerateSPM),
265 )
266 .padding([8, 24])
267 .into()
268 }
269
270 fn error_platform_view(&self) -> AppElement<'_> {
272 if self.platform_error {
273 iced::widget::Container::new(
274 text("Please select at least one platform.")
275 .color([1.0, 0.2, 0.2])
276 .size(16),
277 )
278 .padding([0, 24])
279 .into()
280 } else {
281 iced::widget::Container::new("").into()
282 }
283 }
284
285 fn view_files_checkboxes(&self) -> Vec<AppElement<'_>> {
287 vec![
288 self.checkbox_row("Changelog", self.changelog, Message::ChangelogToggled),
289 self.checkbox_row("Readme", self.readme, Message::ReadmeToggled),
290 self.checkbox_row(
291 "Swift Package Index",
292 self.swift_package_index,
293 Message::SwiftPackageIndexToggled,
294 ),
295 self.checkbox_row("SwiftLint", self.swiftlint, Message::SwiftLintToggled),
296 ]
297 }
298
299 fn view_platforms_checkboxes(&self) -> Vec<AppElement<'_>> {
301 vec![
302 self.checkbox_row("iOS", self.ios, Message::IosToggled),
303 self.checkbox_row("macOS", self.macos, Message::MacOsToggled),
304 self.checkbox_row("tvOS", self.tvos, Message::TvOsToggled),
305 self.checkbox_row("watchOS", self.watchos, Message::WatchOsToggled),
306 self.checkbox_row("visionOS", self.visionos, Message::VisionOsToggled),
307 ]
308 }
309
310 fn checkbox_row<'a>(
312 &self,
313 label: &'a str,
314 value: bool,
315 on_toggle: fn(bool) -> Message,
316 ) -> AppElement<'a> {
317 iced::widget::Container::new(checkbox(value).label(label).on_toggle(on_toggle))
318 .padding([0, 24])
319 .into()
320 }
321}