termusiclib/config/v2/tui/
mod.rs1use std::path::Path;
2
3use anyhow::{Context, Result};
4use serde::{Deserialize, Serialize};
5
6use super::server::ComSettings;
7
8pub mod config_extra;
9pub mod keys;
10pub mod theme;
11
12#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Default)]
13#[serde(default)] #[allow(clippy::module_name_repetitions)]
15pub struct TuiSettings {
16 pub com: MaybeComSettings,
17 #[serde(skip)]
19 pub com_resolved: Option<ComSettings>,
20 pub behavior: BehaviorSettings,
21 pub coverart: CoverArtPosition,
22 #[serde(flatten)]
23 pub theme: theme::ThemeWrap,
24 pub keys: keys::Keys,
25 pub ytdlp: Ytdlp,
26}
27
28impl TuiSettings {
29 pub fn resolve_com(&mut self, tui_path: &Path) -> Result<()> {
33 if self.com_resolved.is_some() {
34 return Ok(());
35 }
36
37 match self.com {
38 MaybeComSettings::ComSettings(ref v) => {
39 self.com_resolved = Some(v.clone());
41 return Ok(());
42 }
43 MaybeComSettings::Same => (),
44 }
45
46 let server_path = tui_path
47 .parent()
48 .context("tui_path should have a parent directory")?
49 .join(super::server::config_extra::FILE_NAME);
50
51 let server_settings =
52 super::server::config_extra::ServerConfigVersionedDefaulted::from_file(server_path)
53 .context("parsing server config")?;
54 self.com_resolved = Some(server_settings.into_settings().com);
55
56 Ok(())
57 }
58
59 #[must_use]
61 pub fn get_com(&self) -> Option<&ComSettings> {
62 self.com_resolved.as_ref()
63 }
64}
65
66#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
67pub struct BehaviorSettings {
68 pub quit_server_on_exit: bool,
70 pub confirm_quit: bool,
72}
73
74impl Default for BehaviorSettings {
75 fn default() -> Self {
76 Self {
77 quit_server_on_exit: true,
78 confirm_quit: true,
79 }
80 }
81}
82
83#[derive(Debug, Clone, Deserialize, Serialize, Default, PartialEq, Eq)]
84#[serde(rename_all = "lowercase")]
85pub enum MaybeComSettings {
86 ComSettings(ComSettings),
87 #[default]
89 Same,
90}
91
92#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq)]
93#[serde(default)] #[derive(Default)]
95pub struct CoverArtPosition {
96 pub align: Alignment,
99 pub size_scale: i8,
101 pub hidden: bool,
103}
104
105#[derive(Debug, Clone, Copy, Deserialize, Serialize, Default, PartialEq, Eq)]
106pub enum Alignment {
107 #[serde(rename = "top right")]
108 TopRight,
109 #[serde(rename = "top left")]
110 TopLeft,
111 #[serde(rename = "bottom right")]
112 #[default]
113 BottomRight,
114 #[serde(rename = "bottom left")]
115 BottomLeft,
116}
117
118#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, Eq, Default)]
119#[serde(default)] pub struct Ytdlp {
121 pub extra_args: String,
123}
124
125mod v1_interop {
126 use super::{
127 Alignment, BehaviorSettings, CoverArtPosition, MaybeComSettings, TuiSettings, Ytdlp,
128 };
129 use crate::config::v1;
130
131 impl From<v1::Alignment> for Alignment {
132 fn from(value: v1::Alignment) -> Self {
133 match value {
134 v1::Alignment::BottomRight => Self::BottomRight,
135 v1::Alignment::BottomLeft => Self::BottomLeft,
136 v1::Alignment::TopRight => Self::TopRight,
137 v1::Alignment::TopLeft => Self::TopLeft,
138 }
139 }
140 }
141
142 #[allow(clippy::cast_possible_truncation)] impl From<v1::Xywh> for CoverArtPosition {
144 fn from(value: v1::Xywh) -> Self {
145 Self {
146 align: value.align.into(),
147 size_scale: value.width_between_1_100.clamp(0, i8::MAX as u32) as i8,
149 hidden: Self::default().hidden,
150 }
151 }
152 }
153
154 impl From<v1::Settings> for TuiSettings {
155 fn from(value: v1::Settings) -> Self {
156 let theme = (&value).into();
157 Self {
158 com: MaybeComSettings::Same,
160 com_resolved: None,
161 behavior: BehaviorSettings {
162 quit_server_on_exit: value.kill_daemon_when_quit,
163 confirm_quit: value.enable_exit_confirmation,
164 },
165 coverart: value.album_photo_xywh.into(),
166 theme,
167 keys: value.keys.into(),
168 ytdlp: Ytdlp::default(),
169 }
170 }
171 }
172
173 #[cfg(test)]
174 mod tests {
175 use super::*;
176
177 #[test]
178 fn should_convert_default_without_error() {
179 let converted: TuiSettings = v1::Settings::default().into();
180
181 assert_eq!(converted.com, MaybeComSettings::Same);
182 assert_eq!(
183 converted.behavior,
184 BehaviorSettings {
185 quit_server_on_exit: true,
186 confirm_quit: true
187 }
188 );
189
190 assert_eq!(
191 converted.coverart,
192 CoverArtPosition {
193 align: Alignment::BottomRight,
194 size_scale: 20,
195 hidden: false
196 }
197 );
198
199 }
203 }
204}