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