modde_ui/app/
fomod_wizard_state.rs1use std::collections::HashMap;
2use std::path::PathBuf;
3
4pub struct FOMODWizardState {
5 pub current_step: usize,
6 pub total_steps: usize,
7 inner: Option<fomod_oxide::installer::Installer>,
8}
9
10impl std::fmt::Debug for FOMODWizardState {
11 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
12 f.debug_struct("FOMODWizardState")
13 .field("current_step", &self.current_step)
14 .field("total_steps", &self.total_steps)
15 .field("has_inner", &self.inner.is_some())
16 .finish()
17 }
18}
19
20impl Clone for FOMODWizardState {
21 fn clone(&self) -> Self {
22 Self {
23 current_step: self.current_step,
24 total_steps: self.total_steps,
25 inner: None,
26 }
27 }
28}
29
30impl Default for FOMODWizardState {
31 fn default() -> Self {
32 Self::new()
33 }
34}
35
36impl FOMODWizardState {
37 #[must_use]
38 pub fn new() -> Self {
39 Self {
40 current_step: 0,
41 total_steps: 0,
42 inner: None,
43 }
44 }
45
46 #[must_use]
47 pub fn with_installer(installer: fomod_oxide::installer::Installer) -> Self {
48 let total = installer.visible_steps().len();
49 Self {
50 current_step: 0,
51 total_steps: total,
52 inner: Some(installer),
53 }
54 }
55
56 #[must_use]
57 pub fn visible_steps(&self) -> Vec<(usize, &fomod_oxide::config::InstallStep)> {
58 match &self.inner {
59 Some(installer) => installer.visible_steps(),
60 None => vec![],
61 }
62 }
63
64 #[must_use]
65 pub fn config(&self) -> Option<&fomod_oxide::config::ModuleConfig> {
66 self.inner
67 .as_ref()
68 .map(fomod_oxide::installer::Installer::config)
69 }
70
71 #[must_use]
72 pub fn module_image_path(&self) -> Option<&str> {
73 self.inner.as_ref()?.module_image_path()
74 }
75
76 #[must_use]
77 pub fn resolve_image(&self, base_path: &std::path::Path, image_path: &str) -> Option<PathBuf> {
78 self.inner.as_ref()?.resolve_image(base_path, image_path)
79 }
80
81 #[must_use]
82 pub fn completion_status(&self) -> fomod_oxide::installer::CompletionStatus {
83 match &self.inner {
84 Some(installer) => installer.completion_status(),
85 None => fomod_oxide::installer::CompletionStatus {
86 total_steps: 0,
87 visible_steps: 0,
88 total_groups: 0,
89 satisfied_groups: 0,
90 },
91 }
92 }
93
94 #[must_use]
95 pub fn validate_step(&self, step_index: usize) -> Vec<fomod_oxide::installer::ValidationHint> {
96 match &self.inner {
97 Some(installer) => installer.validate_step(step_index),
98 None => vec![],
99 }
100 }
101
102 #[must_use]
103 pub fn plugin_type_at(
104 &self,
105 step: usize,
106 group: usize,
107 plugin: usize,
108 ) -> Option<fomod_oxide::config::PluginType> {
109 self.inner.as_ref()?.plugin_type_at(step, group, plugin)
110 }
111
112 #[must_use]
113 pub fn plugin_image_path(&self, step: usize, group: usize, plugin: usize) -> Option<&str> {
114 self.inner.as_ref()?.plugin_image_path(step, group, plugin)
115 }
116
117 #[must_use]
118 pub fn preview_plugin(
119 &self,
120 step: usize,
121 group: usize,
122 plugin: usize,
123 ) -> Vec<fomod_oxide::installer::FileOperation> {
124 match &self.inner {
125 Some(installer) => installer.preview_plugin(step, group, plugin),
126 None => vec![],
127 }
128 }
129
130 #[must_use]
131 pub fn preview_current(&self) -> fomod_oxide::installer::InstallPlan {
132 match &self.inner {
133 Some(installer) => installer.preview_current(),
134 None => fomod_oxide::installer::InstallPlan { operations: vec![] },
135 }
136 }
137
138 #[must_use]
139 pub fn is_ready_to_install(&self) -> bool {
140 match &self.inner {
141 Some(installer) => installer.is_ready_to_install(),
142 None => false,
143 }
144 }
145
146 #[must_use]
147 pub fn group_type_at(
148 &self,
149 step: usize,
150 group: usize,
151 ) -> Option<fomod_oxide::config::GroupType> {
152 self.inner.as_ref()?.group_type_at(step, group)
153 }
154
155 pub fn select(&mut self, step: usize, group: usize, plugin_indices: Vec<usize>) {
156 if let Some(ref mut installer) = self.inner {
157 installer.select(step, group, plugin_indices);
158 }
159 }
160
161 pub fn checkpoint(&mut self) {
162 if let Some(ref mut installer) = self.inner {
163 installer.checkpoint();
164 }
165 }
166
167 pub fn rollback(&mut self) -> bool {
168 match &mut self.inner {
169 Some(installer) => installer.rollback(),
170 None => false,
171 }
172 }
173
174 #[must_use]
175 pub fn history_len(&self) -> usize {
176 match &self.inner {
177 Some(installer) => installer.history_len(),
178 None => 0,
179 }
180 }
181
182 #[must_use]
183 pub fn selections(&self) -> HashMap<(usize, usize), Vec<usize>> {
184 match &self.inner {
185 Some(installer) => installer.selections().clone(),
186 None => HashMap::new(),
187 }
188 }
189
190 #[must_use]
191 pub fn detect_conflicts(&self) -> Vec<String> {
192 match &self.inner {
193 Some(installer) => installer
194 .detect_conflicts()
195 .into_iter()
196 .map(|c| c.destination)
197 .collect(),
198 None => vec![],
199 }
200 }
201
202 #[must_use]
203 pub fn resolve(&self) -> fomod_oxide::installer::InstallPlan {
204 match &self.inner {
205 Some(installer) => installer.resolve(),
206 None => fomod_oxide::installer::InstallPlan { operations: vec![] },
207 }
208 }
209
210 #[must_use]
211 pub fn default_selections(&self) -> Vec<(usize, usize, Vec<usize>)> {
212 let installer = match &self.inner {
213 Some(i) => i,
214 None => return vec![],
215 };
216 let visible = installer.visible_steps();
217 let mut defaults = Vec::new();
218 for &(step_idx, step) in &visible {
219 if let Some(ref groups) = step.optional_file_groups {
220 for (group_idx, group) in groups.groups.iter().enumerate() {
221 let sel = fomod_oxide::Installer::default_selections(group);
222 defaults.push((step_idx, group_idx, sel));
223 }
224 }
225 }
226 defaults
227 }
228}