gui_server_api/navigation/
qrscanner.rs1use std::fmt;
7
8use app_manifest::QrPriority;
9use server::WithAppId;
10use xous::AppId;
11
12#[derive(Debug, Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
25pub struct ScanQrMatchedRule {
26 pub rule_id: String,
27 pub priority: QrPriority,
28 pub sub_rule_id: String,
31}
32
33#[derive(Debug, Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
37pub struct ScanQrMatchingApp {
38 #[rkyv(with = WithAppId)]
39 pub id: AppId,
40 pub matched_rules: Vec<ScanQrMatchedRule>,
41}
42
43#[derive(Debug, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
44pub struct ScanQrOptions {
45 pub header_title: String,
46 pub header_left_icon: String,
47 pub header_left_text: String,
48 pub header_right_icon: String,
49 pub header_right_text: String,
50 pub message: String,
51 pub button_icon: String,
52 pub button_text: String,
53 pub request_matching_apps: bool,
54}
55
56impl Default for ScanQrOptions {
57 fn default() -> Self {
58 Self {
59 header_title: String::new(),
60 header_left_icon: String::from("chevron-left"),
61 header_left_text: String::new(),
62 header_right_icon: String::new(),
63 header_right_text: String::new(),
64 message: String::new(),
65 button_icon: String::new(),
66 button_text: String::new(),
67 request_matching_apps: false,
68 }
69 }
70}
71
72impl ScanQrOptions {
73 pub fn new() -> Self {
74 Self {
75 header_title: String::new(),
76 header_left_icon: String::new(),
77 header_left_text: String::new(),
78 header_right_icon: String::new(),
79 header_right_text: String::new(),
80 message: String::new(),
81 button_icon: String::new(),
82 button_text: String::new(),
83 request_matching_apps: false,
84 }
85 }
86
87 pub fn from_slice(data: &[u8]) -> Option<Self> {
88 let Ok(archived) = rkyv::access::<ArchivedScanQrOptions, rkyv::rancor::Error>(data) else {
89 return None;
90 };
91 rkyv::deserialize::<Self, rkyv::rancor::Error>(archived).ok()
92 }
93
94 pub fn serialize(&self) -> Vec<u8> { rkyv::to_bytes::<rkyv::rancor::Error>(self).unwrap().to_vec() }
95}
96
97#[derive(Debug, Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
98pub struct MatchedQrResult {
99 pub scan_result: ScanQrResult,
100 pub matched_rules: Vec<ScanQrMatchedRule>,
101}
102
103impl MatchedQrResult {
104 pub fn from_slice(data: &[u8]) -> Option<Self> {
105 let Ok(archived) = rkyv::access::<ArchivedMatchedQrResult, rkyv::rancor::Error>(data) else {
106 return None;
107 };
108 rkyv::deserialize::<Self, rkyv::rancor::Error>(archived).ok()
109 }
110
111 pub fn serialize(&self) -> Vec<u8> { rkyv::to_bytes::<rkyv::rancor::Error>(self).unwrap().to_vec() }
112}
113
114#[derive(Clone, rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)]
115pub enum ScanQrResult {
116 Qr { data: Vec<u8>, matching_apps: Option<Vec<ScanQrMatchingApp>> },
117 Ur2 { ur_type: String, data: Vec<u8>, matching_apps: Option<Vec<ScanQrMatchingApp>> },
118 LeftClicked,
119 RightClicked,
120 ButtonClicked,
121}
122
123impl fmt::Debug for ScanQrResult {
126 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
127 match self {
128 Self::Qr { data, matching_apps } => formatter
129 .debug_struct("Qr")
130 .field("data_len", &data.len())
131 .field("matching_apps", matching_apps)
132 .finish_non_exhaustive(),
133 Self::Ur2 { ur_type, data, matching_apps } => formatter
134 .debug_struct("Ur2")
135 .field("ur_type", ur_type)
136 .field("data_len", &data.len())
137 .field("matching_apps", matching_apps)
138 .finish_non_exhaustive(),
139 Self::LeftClicked => formatter.write_str("LeftClicked"),
140 Self::RightClicked => formatter.write_str("RightClicked"),
141 Self::ButtonClicked => formatter.write_str("ButtonClicked"),
142 }
143 }
144}
145
146impl ScanQrResult {
147 pub fn new_qr(data: &[u8]) -> Self { Self::Qr { data: data.to_vec(), matching_apps: None } }
148
149 pub fn new_ur2(ur_type: String, data: &[u8]) -> Self {
150 Self::Ur2 { ur_type, data: data.to_vec(), matching_apps: None }
151 }
152
153 pub fn with_matching_apps(self, matching_apps: Vec<ScanQrMatchingApp>) -> Self {
154 match self {
155 Self::Qr { data, .. } => Self::Qr { data, matching_apps: Some(matching_apps) },
156 Self::Ur2 { ur_type, data, .. } => {
157 Self::Ur2 { ur_type, data, matching_apps: Some(matching_apps) }
158 }
159 other => other,
160 }
161 }
162
163 pub fn new_cancelled() -> Self { Self::LeftClicked }
164
165 pub fn from_slice(data: &[u8]) -> Option<Self> {
166 let Ok(archived) = rkyv::access::<ArchivedScanQrResult, rkyv::rancor::Error>(data) else {
167 return None;
168 };
169 rkyv::deserialize::<Self, rkyv::rancor::Error>(archived).ok()
170 }
171
172 pub fn serialize(&self) -> Vec<u8> { rkyv::to_bytes::<rkyv::rancor::Error>(self).unwrap().to_vec() }
173}