Skip to main content

modde_ui/app/
fomod_wizard_state.rs

1use 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}