1use std::time::Duration;
10
11use num_derive::{FromPrimitive, ToPrimitive};
12use num_traits::{FromPrimitive, ToPrimitive};
13use server::{AsScalar, FromScalar};
14
15use crate::macros::*;
16
17#[derive(
18 Debug, Copy, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize, FromPrimitive, ToPrimitive,
19)]
20pub enum BoardRevision {
21 D1,
23
24 D6,
26}
27
28impl FromScalar<1> for BoardRevision {
29 fn from_scalar(value: [u32; 1]) -> Self { Self::from_u32(value[0]).unwrap() }
30}
31
32impl AsScalar<1> for BoardRevision {
33 fn as_scalar(&self) -> [u32; 1] { [self.to_u32().unwrap()] }
34}
35
36create_modules! {
37 SystemTheme,
38 ScreenBrightness,
39 OnboardingStatus,
40 Locale,
41 DeviceName,
42 ShowSecurityWords,
43 AutoLock,
44 EnvoyTimeSync,
45 UseStandardTimeFormat,
46 TimeZone,
47 DebugTouch,
48 AirlockMode,
49 TouchOffset,
50 MagicBackupEnabled,
51 NfcEnabled,
52 BluetoothEnabled,
53 CameraEnabled,
54 UsbEnabled,
55 DeveloperMode,
56}
57
58global_scalar! {
59 system,
63 #[derive(FromPrimitive, ToPrimitive)]
64 pub enum SystemTheme {
65 Dark,
66 Light,
67 }
68}
69
70impl FromScalar<1> for SystemTheme {
71 fn from_scalar(value: [u32; 1]) -> Self { Self::from_u32(value[0]).unwrap() }
72}
73
74impl AsScalar<1> for SystemTheme {
75 fn as_scalar(&self) -> [u32; 1] { [self.to_u32().unwrap()] }
76}
77
78global_scalar! {
79 system,
81 pub struct ScreenBrightness(pub u8);
82}
83
84impl FromScalar<1> for ScreenBrightness {
85 fn from_scalar(value: [u32; 1]) -> Self { Self(value[0] as u8) }
86}
87
88impl AsScalar<1> for ScreenBrightness {
89 fn as_scalar(&self) -> [u32; 1] { [self.0 as u32] }
90}
91
92global_archive! {
93 encrypted,
95 #[derive(Default)]
96 pub enum OnboardingStatus {
97 #[default]
98 NotComplete,
99 Complete,
100 }
101}
102
103impl OnboardingStatus {
104 pub fn is_complete(&self) -> bool { matches!(self, Self::Complete) }
105}
106
107impl ArchivedOnboardingStatus {
108 pub fn is_complete(&self) -> bool { matches!(self, Self::Complete) }
109}
110
111global_scalar! {
112 system,
114 #[derive(Default, FromPrimitive, ToPrimitive)]
115 pub enum Locale {
116 #[default]
117 EnglishUS,
118 }
119}
120
121impl FromScalar<1> for Locale {
122 fn from_scalar(value: [u32; 1]) -> Self { Self::from_u32(value[0]).unwrap() }
123}
124
125impl AsScalar<1> for Locale {
126 fn as_scalar(&self) -> [u32; 1] { [self.to_u32().unwrap()] }
127}
128
129impl Locale {
130 pub fn lang(&self) -> &str {
131 match self {
132 Self::EnglishUS => "en",
133 }
134 }
135}
136
137global_archive! {
138 system,
140 pub struct DeviceName(pub String);
141}
142
143impl From<&str> for DeviceName {
144 fn from(value: &str) -> Self { Self(String::from(value)) }
145}
146
147impl DeviceName {
148 pub const DEFAULT: &str = "Passport Prime";
149}
150
151global_scalar! {
152 system,
154 pub struct ShowSecurityWords(pub bool);
155}
156
157impl FromScalar<1> for ShowSecurityWords {
158 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
159}
160
161impl AsScalar<1> for ShowSecurityWords {
162 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
163}
164
165global_scalar! {
166 system,
168 pub struct AutoLock(pub Duration);
169}
170
171impl FromScalar<2> for AutoLock {
172 fn from_scalar(value: [u32; 2]) -> Self {
173 Self(Duration::from_secs(value[0] as u64) + Duration::from_millis(value[1] as u64))
174 }
175}
176
177impl AsScalar<2> for AutoLock {
178 fn as_scalar(&self) -> [u32; 2] { [self.0.as_secs() as u32, self.0.subsec_millis()] }
179}
180
181global_scalar! {
182 system,
184 pub struct EnvoyTimeSync(pub bool);
185}
186
187impl FromScalar<1> for EnvoyTimeSync {
188 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
189}
190
191impl AsScalar<1> for EnvoyTimeSync {
192 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
193}
194
195global_scalar! {
196 system,
198 pub struct UseStandardTimeFormat(pub bool);
199}
200
201impl FromScalar<1> for UseStandardTimeFormat {
202 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
203}
204
205impl AsScalar<1> for UseStandardTimeFormat {
206 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
207}
208
209global_archive! {
210 system,
212 pub struct TimeZone {
213 pub name: String,
214 pub data: Vec<u8>
215 }
216}
217
218impl Default for TimeZone {
219 fn default() -> Self {
220 Self {
221 name: String::from("America/New_York"),
222 data: include_bytes!("../assets/america_new_york.tzif").to_vec(),
223 }
224 }
225}
226
227impl TimeZone {
228 pub fn now(&self) -> jiff::Zoned { jiff::Timestamp::now().to_zoned(self.timezone()) }
229
230 pub fn timezone(&self) -> jiff::tz::TimeZone {
231 jiff::tz::TimeZone::tzif(&self.name, &self.data).unwrap_or_else(|_| TimeZone::default().timezone())
232 }
233
234 pub fn name(&self) -> &str { &self.name }
235
236 pub fn abbreviation(&self, timestamp: jiff::Timestamp) -> String {
237 let tz = self.timezone();
238 let info = tz.to_offset_info(timestamp);
239 info.abbreviation().into()
240 }
241}
242
243global_scalar! {
244 system,
245 pub struct DebugTouch(pub bool);
246}
247
248impl FromScalar<1> for DebugTouch {
249 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
250}
251
252impl AsScalar<1> for DebugTouch {
253 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
254}
255
256global_scalar! {
257 system,
258 #[derive(FromPrimitive, ToPrimitive)]
259 pub enum AirlockMode {
260 Disabled,
261 ReadOnly,
262 ReadWrite,
263 }
264}
265
266impl FromScalar<1> for AirlockMode {
267 fn from_scalar(value: [u32; 1]) -> Self { Self::from_u32(value[0]).unwrap() }
268}
269
270impl AsScalar<1> for AirlockMode {
271 fn as_scalar(&self) -> [u32; 1] { [self.to_u32().unwrap()] }
272}
273
274global_scalar! {
275 system,
276 pub struct TouchOffset(pub i32);
277}
278
279impl FromScalar<1> for TouchOffset {
280 fn from_scalar(value: [u32; 1]) -> Self { Self(i32::from_scalar(value)) }
281}
282
283impl AsScalar<1> for TouchOffset {
284 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
285}
286
287global_scalar! {
288 system,
289 pub struct MagicBackupEnabled(pub bool);
290}
291
292global_scalar! {
293 system,
294 pub struct NfcEnabled(pub bool);
295}
296
297global_scalar! {
298 system,
299 pub struct BluetoothEnabled(pub bool);
300}
301
302global_scalar! {
303 system,
304 pub struct CameraEnabled(pub bool);
305}
306
307global_scalar! {
308 system,
309 pub struct UsbEnabled(pub bool);
310}
311
312global_scalar! {
313 encrypted,
314 pub struct DeveloperMode(pub bool);
315}
316
317impl FromScalar<1> for MagicBackupEnabled {
318 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
319}
320
321impl AsScalar<1> for MagicBackupEnabled {
322 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
323}
324
325impl FromScalar<1> for NfcEnabled {
326 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
327}
328
329impl AsScalar<1> for NfcEnabled {
330 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
331}
332
333impl FromScalar<1> for BluetoothEnabled {
334 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
335}
336
337impl AsScalar<1> for BluetoothEnabled {
338 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
339}
340
341impl FromScalar<1> for CameraEnabled {
342 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
343}
344
345impl AsScalar<1> for CameraEnabled {
346 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
347}
348
349impl FromScalar<1> for UsbEnabled {
350 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
351}
352
353impl AsScalar<1> for UsbEnabled {
354 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
355}
356
357impl FromScalar<1> for DeveloperMode {
358 fn from_scalar(value: [u32; 1]) -> Self { Self(bool::from_scalar(value)) }
359}
360
361impl AsScalar<1> for DeveloperMode {
362 fn as_scalar(&self) -> [u32; 1] { self.0.as_scalar() }
363}
364
365#[cfg(test)]
366mod tests {
367 use super::*;
368
369 #[test]
370 fn default_timezone() {
371 let tz = TimeZone::default();
372 assert_eq!(tz.name(), "America/New_York");
373 let timezone = tz.timezone();
374 assert_eq!(timezone.iana_name(), Some("America/New_York"));
375 }
376}