1use std::path::PathBuf;
2
3use fastpack_core::types::config::PackerConfig;
4use serde::{Deserialize, Serialize};
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)]
7pub enum Language {
8 #[default]
9 En,
10 Fr,
12 Es,
14 De,
16 It,
18 Pt,
20 Ja,
22 Zh,
24 Ko,
26}
27
28impl Language {
29 pub fn code(self) -> &'static str {
31 match self {
32 Self::En => "en",
33 Self::Fr => "fr",
34 Self::Es => "es",
35 Self::De => "de",
36 Self::It => "it",
37 Self::Pt => "pt",
38 Self::Ja => "ja",
39 Self::Zh => "zh",
40 Self::Ko => "ko",
41 }
42 }
43
44 pub fn display(self) -> &'static str {
46 match self {
47 Self::En => "English",
48 Self::Fr => "Français",
49 Self::Es => "Español",
50 Self::De => "Deutsch",
51 Self::It => "Italiano",
52 Self::Pt => "Português",
53 Self::Ja => "日本語",
54 Self::Zh => "中文(简体)",
55 Self::Ko => "한국어",
56 }
57 }
58
59 pub const ALL: &'static [Language] = &[
61 Self::En,
62 Self::Fr,
63 Self::Es,
64 Self::De,
65 Self::It,
66 Self::Pt,
67 Self::Ja,
68 Self::Zh,
69 Self::Ko,
70 ];
71}
72
73#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
75pub struct KeyBind {
76 pub key: String,
77 #[serde(default)]
78 pub ctrl: bool,
79 #[serde(default)]
80 pub shift: bool,
81 #[serde(default)]
82 pub alt: bool,
83}
84
85impl KeyBind {
86 pub fn ctrl(key: &str) -> Self {
87 Self {
88 key: key.to_owned(),
89 ctrl: true,
90 shift: false,
91 alt: false,
92 }
93 }
94
95 pub fn bare(key: &str) -> Self {
96 Self {
97 key: key.to_owned(),
98 ctrl: false,
99 shift: false,
100 alt: false,
101 }
102 }
103
104 pub fn display(&self) -> String {
105 let mut parts: Vec<&str> = Vec::new();
106 if self.ctrl {
107 parts.push("Ctrl");
108 }
109 if self.alt {
110 parts.push("Alt");
111 }
112 if self.shift {
113 parts.push("Shift");
114 }
115 parts.push(self.key.as_str());
116 parts.join("+")
117 }
118
119 pub fn default_new_project() -> Self {
120 Self::ctrl("N")
121 }
122 pub fn default_open_project() -> Self {
123 Self::ctrl("O")
124 }
125 pub fn default_save_project() -> Self {
126 Self::ctrl("S")
127 }
128 pub fn default_export() -> Self {
129 Self::ctrl("P")
130 }
131 pub fn default_anim_preview() -> Self {
132 Self::bare("P")
133 }
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
138pub struct Keybinds {
139 #[serde(default = "KeyBind::default_new_project")]
140 pub new_project: KeyBind,
141 #[serde(default = "KeyBind::default_open_project")]
142 pub open_project: KeyBind,
143 #[serde(default = "KeyBind::default_save_project")]
144 pub save_project: KeyBind,
145 #[serde(default = "KeyBind::default_export")]
146 pub export: KeyBind,
147 #[serde(default = "KeyBind::default_anim_preview")]
148 pub anim_preview: KeyBind,
149}
150
151impl Default for Keybinds {
152 fn default() -> Self {
153 Self {
154 new_project: KeyBind::default_new_project(),
155 open_project: KeyBind::default_open_project(),
156 save_project: KeyBind::default_save_project(),
157 export: KeyBind::default_export(),
158 anim_preview: KeyBind::default_anim_preview(),
159 }
160 }
161}
162
163#[derive(Debug, Clone, Serialize, Deserialize)]
165pub struct Preferences {
166 #[serde(default = "default_true")]
168 pub dark_mode: bool,
169 #[serde(default = "default_true")]
171 pub auto_check_updates: bool,
172 #[serde(default)]
174 pub default_config: PackerConfig,
175 #[serde(default)]
177 pub language: Language,
178 #[serde(default)]
180 pub keybinds: Keybinds,
181 #[serde(default = "default_ui_scale")]
183 pub ui_scale: f32,
184}
185
186fn default_true() -> bool {
187 true
188}
189
190fn default_ui_scale() -> f32 {
191 1.0
192}
193
194impl Default for Preferences {
195 fn default() -> Self {
196 Self {
197 dark_mode: true,
198 auto_check_updates: true,
199 default_config: PackerConfig::default(),
200 language: Language::En,
201 keybinds: Keybinds::default(),
202 ui_scale: 1.0,
203 }
204 }
205}
206
207impl Preferences {
208 pub fn load() -> Self {
210 prefs_path()
211 .and_then(|p| std::fs::read_to_string(p).ok())
212 .and_then(|text| toml::from_str(&text).ok())
213 .unwrap_or_default()
214 }
215
216 pub fn save(&self) {
218 let Some(path) = prefs_path() else { return };
219 if let Some(parent) = path.parent() {
220 let _ = std::fs::create_dir_all(parent);
221 }
222 if let Ok(text) = toml::to_string_pretty(self) {
223 let _ = std::fs::write(path, text.as_bytes());
224 }
225 }
226}
227
228fn prefs_path() -> Option<PathBuf> {
229 dirs::config_dir().map(|d| d.join("FastPack").join("prefs.toml"))
230}