Skip to main content

thedes_app/
settings.rs

1use std::{fmt, path::PathBuf};
2
3use thedes_settings::{AudioSinkType, Settings};
4
5pub use thedes_settings::SaveError;
6use thedes_tui::{
7    cancellability::Cancellable,
8    core::{
9        App,
10        audio::{self, Volume, device::SetVolumeError},
11    },
12    menu::{self, Menu},
13    slidebar::{self, Slidebar},
14};
15use thiserror::Error;
16
17#[derive(Debug, Error)]
18pub enum InitError {
19    #[error("Failed to create main settings menu")]
20    MainSettingsMenu(#[source] menu::Error),
21    #[error("Failed to create audio settings menu")]
22    AudioSettingsMenu(#[source] menu::Error),
23}
24
25#[derive(Debug, Error)]
26pub enum LoadError {
27    #[error(transparent)]
28    LoadSettings(#[from] thedes_settings::LoadError),
29    #[error("Failed to initialize component")]
30    Init(#[from] InitError),
31}
32
33#[derive(Debug, Error)]
34pub enum Error {
35    #[error("Failed to run main settings menu")]
36    MainSettingsMenu(#[source] menu::Error),
37    #[error("Failed to run audio settings menu")]
38    AudioSettingsMenu(#[source] menu::Error),
39    #[error("Failed to set audio output volume")]
40    AudioSetVolume(#[from] SetVolumeError),
41    #[error("Failed to manipulate slidebar")]
42    Slidebar(#[from] slidebar::Error),
43    #[error("Failed to save settings")]
44    Save(#[from] SaveError),
45}
46
47#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
48enum MainSettingsItem {
49    Audio,
50}
51
52impl fmt::Display for MainSettingsItem {
53    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
54        f.write_str(match self {
55            Self::Audio => "Audio Settings",
56        })
57    }
58}
59
60#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
61enum AudioSettingsItem {
62    Music,
63    Fx,
64}
65
66impl fmt::Display for AudioSettingsItem {
67    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
68        f.write_str(match self {
69            Self::Music => "Set Music Volume",
70            Self::Fx => "Set FX Volume",
71        })
72    }
73}
74
75#[derive(Debug, Clone)]
76pub struct Component {
77    main_settings_menu: Menu<MainSettingsItem, Cancellable>,
78    audio_settings_menu: Menu<AudioSettingsItem, Cancellable>,
79    audio_music_slidebar: Slidebar,
80    audio_fx_slidebar: Slidebar,
81    settings: Settings,
82    path: PathBuf,
83}
84
85impl Component {
86    pub fn new(path: PathBuf, settings: Settings) -> Result<Self, InitError> {
87        let main_settings_menu = Menu::from_cancellation(
88            "% Settings %",
89            [MainSettingsItem::Audio],
90            Cancellable::new(false),
91        )
92        .map_err(InitError::MainSettingsMenu)?;
93
94        let audio_settings_menu = Menu::from_cancellation(
95            "((|>  Audio Settings  <|))",
96            [AudioSettingsItem::Music, AudioSettingsItem::Fx],
97            Cancellable::new(false),
98        )
99        .map_err(InitError::AudioSettingsMenu)?;
100
101        let audio_music_slidebar = Slidebar::new(
102            "Set Music Volume",
103            slidebar::Config {
104                ui_size: 17,
105                logical_size: 256,
106                logical_current: settings
107                    .audio()
108                    .volume(AudioSinkType::Music)
109                    .into(),
110            },
111        );
112
113        let audio_fx_slidebar = Slidebar::new(
114            "Set FX Volume",
115            slidebar::Config {
116                ui_size: 17,
117                logical_size: 256,
118                logical_current: settings
119                    .audio()
120                    .volume(AudioSinkType::Fx)
121                    .into(),
122            },
123        );
124
125        Ok(Self {
126            path,
127            settings,
128            main_settings_menu,
129            audio_settings_menu,
130            audio_music_slidebar,
131            audio_fx_slidebar,
132        })
133    }
134
135    pub async fn load(path: PathBuf) -> Result<Self, LoadError> {
136        let settings = Settings::load_or_default(&path).await;
137        Ok(Self::new(path, settings)?)
138    }
139
140    pub async fn save(&self) -> Result<(), SaveError> {
141        self.settings.save(&self.path).await?;
142        Ok(())
143    }
144
145    pub fn values(&self) -> &Settings {
146        &self.settings
147    }
148
149    pub fn values_mut(&mut self) -> &mut Settings {
150        &mut self.settings
151    }
152
153    pub async fn run(&mut self, app: &mut App) -> Result<(), Error> {
154        loop {
155            self.main_settings_menu
156                .run(app)
157                .await
158                .map_err(Error::MainSettingsMenu)?;
159            match self.main_settings_menu.output() {
160                Some(MainSettingsItem::Audio) => loop {
161                    self.audio_settings_menu
162                        .run(app)
163                        .await
164                        .map_err(Error::AudioSettingsMenu)?;
165
166                    match self.audio_settings_menu.output() {
167                        Some(AudioSettingsItem::Music) => {
168                            self.audio_music_slidebar
169                                .run(app, |app, current| {
170                                    let level = current as Volume;
171                                    self.settings.audio_mut().set_volume(
172                                        AudioSinkType::Music,
173                                        level,
174                                    );
175                                    app.audio_controller.queue([
176                                        audio::Command::new_set_volume(
177                                            AudioSinkType::Music,
178                                            level,
179                                        ),
180                                    ]);
181                                    _ = app.audio_controller.flush();
182                                })
183                                .await?;
184                        },
185
186                        Some(AudioSettingsItem::Fx) => {
187                            self.audio_fx_slidebar
188                                .run(app, |app, current| {
189                                    let level = current as Volume;
190                                    self.settings
191                                        .audio_mut()
192                                        .set_volume(AudioSinkType::Fx, level);
193                                    app.audio_controller.queue([
194                                        audio::Command::new_set_volume(
195                                            AudioSinkType::Fx,
196                                            level,
197                                        ),
198                                    ]);
199                                    _ = app.audio_controller.flush();
200                                })
201                                .await?;
202                        },
203
204                        None => break,
205                    }
206                },
207                None => break,
208            }
209        }
210
211        self.save().await?;
212
213        Ok(())
214    }
215}