1 // Copyright (C) 2024 Huawei Device Co., Ltd.
2 // Licensed under the Apache License, Version 2.0 (the "License");
3 // you may not use this file except in compliance with the License.
4 // You may obtain a copy of the License at
5 //
6 // http://www.apache.org/licenses/LICENSE-2.0
7 //
8 // Unless required by applicable law or agreed to in writing, software
9 // distributed under the License is distributed on an "AS IS" BASIS,
10 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 // See the License for the specific language governing permissions and
12 // limitations under the License.
13
14 #![allow(clippy::bool_assert_comparison)]
15
16 const DOWNLOAD_FILE: &str = "request_agent_download_file\0";
17 const DOWNLOAD_SUCCESS: &str = "request_agent_download_success\0";
18 const DOWNLOAD_FAIL: &str = "request_agent_download_fail\0";
19 const UPLOAD_FILE: &str = "request_agent_upload_file\0";
20 const UPLOAD_SUCCESS: &str = "request_agent_upload_success\0";
21 const UPLOAD_FAIL: &str = "request_agent_upload_fail\0";
22 const TASK_COUNT: &str = "request_agent_task_count\0";
23 const DOWNLOAD_COMPLETE: &str = "request_agent_download_complete\0";
24
25 use super::database::CustomizedNotification;
26 use super::ffi::{GetSystemResourceString, NotifyContent, ProgressCircle};
27 use super::notify_flow::{GroupProgress, ProgressNotify};
28 use crate::config::Action;
29
progress_percentage(current: u64, total: u64) -> String30 fn progress_percentage(current: u64, total: u64) -> String {
31 if total == 0 {
32 return "100%".to_string();
33 }
34 format!(
35 "{}.{:02}%",
36 current * 100 / total,
37 current * 100 % total * 100 / total
38 )
39 }
40
progress_size(current: u64) -> String41 fn progress_size(current: u64) -> String {
42 if current < 1024 {
43 format!("{}B", current)
44 } else if current < 1024 * 1024 {
45 format!("{:.2}KB", current as f64 / 1024.0)
46 } else if current < 1024 * 1024 * 1024 {
47 format!("{:.2}MB", current as f64 / 1024.0 / 1024.0)
48 } else {
49 format!("{:.2}GB", current as f64 / 1024.0 / 1024.0 / 1024.0)
50 }
51 }
52
53 impl NotifyContent {
task_eventual_notify( mut customized: Option<CustomizedNotification>, action: Action, task_id: u32, uid: u32, file_name: String, is_successful: bool, ) -> Self54 pub(crate) fn task_eventual_notify(
55 mut customized: Option<CustomizedNotification>,
56 action: Action,
57 task_id: u32,
58 uid: u32,
59 file_name: String,
60 is_successful: bool,
61 ) -> Self {
62 let title = customized
63 .as_mut()
64 .and_then(|c| c.title.take())
65 .unwrap_or_else(|| match action {
66 Action::Download => {
67 if is_successful {
68 GetSystemResourceString(DOWNLOAD_SUCCESS)
69 } else {
70 GetSystemResourceString(DOWNLOAD_FAIL)
71 }
72 }
73 Action::Upload => {
74 if is_successful {
75 GetSystemResourceString(UPLOAD_SUCCESS)
76 } else {
77 GetSystemResourceString(UPLOAD_FAIL)
78 }
79 }
80 _ => unreachable!(),
81 });
82 let text = customized.and_then(|c| c.text).unwrap_or(file_name);
83
84 Self {
85 title,
86 text,
87 request_id: task_id,
88 uid,
89 live_view: false,
90 progress_circle: ProgressCircle::close(),
91 x_mark: false,
92 }
93 }
94
task_progress_notify( mut customized: Option<CustomizedNotification>, info: &ProgressNotify, ) -> Self95 pub(crate) fn task_progress_notify(
96 mut customized: Option<CustomizedNotification>,
97 info: &ProgressNotify,
98 ) -> Self {
99 let title = customized
100 .as_mut()
101 .and_then(|c| c.title.take())
102 .unwrap_or_else(|| match info.action {
103 Action::Download => {
104 let title = GetSystemResourceString(DOWNLOAD_FILE);
105 match info.total {
106 Some(total) => {
107 title.replace("%s", &progress_percentage(info.processed, total))
108 }
109 None => title.replace("%s", &progress_size(info.processed)),
110 }
111 }
112 Action::Upload => {
113 let title = GetSystemResourceString(UPLOAD_FILE);
114 if let Some((current_count, total_count)) = info.multi_upload {
115 title.replace("%s", &format!("{}/{}", current_count, total_count))
116 } else {
117 match info.total {
118 Some(total) => {
119 title.replace("%s", &progress_percentage(info.processed, total))
120 }
121 None => title.replace("%s", &progress_size(info.processed)),
122 }
123 }
124 }
125 _ => unreachable!(),
126 });
127
128 let text = customized
129 .and_then(|c| c.text.clone())
130 .unwrap_or_else(|| info.file_name.clone());
131
132 let progress_circle = match info.total {
133 Some(total) => ProgressCircle::open(info.processed, total),
134 None => ProgressCircle::close(),
135 };
136
137 Self {
138 title,
139 text,
140 request_id: info.task_id,
141 uid: info.uid as u32,
142 live_view: true,
143 progress_circle,
144 x_mark: true,
145 }
146 }
147
group_eventual_notify( mut customized: Option<CustomizedNotification>, action: Action, group_id: u32, uid: u32, current_size: u64, successful_count: i32, failed_count: i32, ) -> Self148 pub(crate) fn group_eventual_notify(
149 mut customized: Option<CustomizedNotification>,
150 action: Action,
151 group_id: u32,
152 uid: u32,
153 current_size: u64,
154 successful_count: i32,
155 failed_count: i32,
156 ) -> Self {
157 let text_download_complete = GetSystemResourceString(DOWNLOAD_COMPLETE);
158 let text_download = text_download_complete.replace("%s", &progress_size(current_size).to_string());
159 let title = customized
160 .as_mut()
161 .and_then(|c| c.title.take())
162 .unwrap_or_else(|| match action {
163 Action::Download => text_download,
164 Action::Upload => format!("上传完成 {}", progress_size(current_size)),
165 _ => unreachable!(),
166 });
167
168 let text_task_count = GetSystemResourceString(TASK_COUNT);
169 let text_count = if text_task_count.contains("%d") {
170 text_task_count
171 .replacen("%d", &successful_count.to_string(), 1)
172 .replacen("%d", &failed_count.to_string(), 1)
173 } else {
174 text_task_count
175 .replace("%1$d", &successful_count.to_string())
176 .replace("%2$d", &failed_count.to_string())
177 };
178
179 let text = customized
180 .and_then(|c| c.text)
181 .unwrap_or(text_count);
182
183 Self {
184 title,
185 text,
186 request_id: group_id,
187 uid,
188 live_view: false,
189 progress_circle: ProgressCircle::close(),
190 x_mark: false,
191 }
192 }
193
group_progress_notify( mut customized: Option<CustomizedNotification>, action: Action, group_id: u32, uid: u32, group_progress: &GroupProgress, ) -> Self194 pub(crate) fn group_progress_notify(
195 mut customized: Option<CustomizedNotification>,
196 action: Action,
197 group_id: u32,
198 uid: u32,
199 group_progress: &GroupProgress,
200 ) -> Self {
201 let title = customized
202 .as_mut()
203 .and_then(|c| c.title.take())
204 .unwrap_or_else(|| match action {
205 Action::Download => {
206 let title = GetSystemResourceString(DOWNLOAD_FILE);
207 title.replace("%s", &progress_size(group_progress.processed()))
208 }
209 Action::Upload => {
210 let title = GetSystemResourceString(UPLOAD_FILE);
211 title.replace("%s", &progress_size(group_progress.processed()))
212 }
213 _ => unreachable!(),
214 });
215
216 let (successful, failed) = (group_progress.successful(), group_progress.failed());
217 let text_task_count = GetSystemResourceString(TASK_COUNT);
218 let text_count = if text_task_count.contains("%d") {
219 text_task_count
220 .replacen("%d", &successful.to_string(), 1)
221 .replacen("%d", &failed.to_string(), 1)
222 } else {
223 text_task_count
224 .replace("%1$d", &successful.to_string())
225 .replace("%2$d", &failed.to_string())
226 };
227
228 let text = customized
229 .and_then(|c| c.text)
230 .unwrap_or(text_count);
231
232 let progress_circle =
233 ProgressCircle::open((successful + failed) as u64, group_progress.total() as u64);
234 Self {
235 title,
236 text,
237 request_id: group_id,
238 uid,
239 live_view: true,
240 progress_circle,
241 x_mark: false,
242 }
243 }
244 }
245
246 impl ProgressCircle {
close() -> Self247 pub(crate) fn close() -> Self {
248 Self {
249 open: false,
250 current: 0,
251 total: 0,
252 }
253 }
open(mut current: u64, mut total: u64) -> Self254 pub(crate) fn open(mut current: u64, mut total: u64) -> Self {
255 while total > i32::MAX as u64 {
256 total >>= 1;
257 current >>= 1;
258 }
259 Self {
260 open: true,
261 current,
262 total,
263 }
264 }
265 }
266
267 #[cfg(test)]
268 mod ut_typology {
269 include!("../../../tests/ut/service/notification_bar/ut_typology.rs");
270 }
271