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