use std::rc::Rc;
use lieui::prelude::*;
struct Report {
primes: usize,
elapsed_ms: u128,
cancelled: bool,
}
struct Demo {
report: Signal<String>,
done: Signal<u32>,
}
impl Demo {
fn start(&self, cx: &mut Ctx) {
cx.spawn_task_busy("正在统计 2000 万以内的质数…", |ctx| {
let started = std::time::Instant::now();
let limit = 20_000_000u64;
let segments = 40u64;
let mut primes = 0usize;
let mut n = 2u64;
for seg in 0..segments {
let end = limit * (seg + 1) / segments;
while n <= end {
if is_prime(n) {
primes += 1;
}
n += 1;
}
ctx.progress(seg as usize + 1, segments as usize);
if ctx.is_cancelled() {
return Report {
primes,
elapsed_ms: started.elapsed().as_millis(),
cancelled: true,
};
}
}
Report {
primes,
elapsed_ms: started.elapsed().as_millis(),
cancelled: false,
}
});
}
}
fn is_prime(n: u64) -> bool {
if n < 2 {
return false;
}
let mut i = 2;
while i * i <= n {
if n.is_multiple_of(i) {
return false;
}
i += 1;
}
true
}
impl ViewModel for Demo {
fn view(self: &Rc<Self>, v: &mut ViewBuf) {
v.column(|c| {
c.center();
c.gap(12.0);
c.text("后台任务 + loading 遮罩").font_size(18.0);
c.text("点按钮起一个耗时任务;遮罩上的「取消」可中断它")
.font_size(12.0)
.color(Color::rgba(0x66, 0x66, 0x66, 255));
c.text(format!("完成任务数:{}", self.done.get())).font_size(13.0);
c.text(self.report.get()).font_size(13.0);
c.button("跑一个耗时任务").on_tap_with({
let me = Rc::clone(self);
move |cx| me.start(cx)
});
});
}
fn on_external(self: &Rc<Self>, _cx: &mut Ctx, data: ExternalData) {
if let Some(ev) = data.downcast_ref::<TaskEvent>() {
if let Some(r) = ev.payload.downcast_ref::<Report>() {
self.report.set(format!(
"上批结果:{} 个质数,耗时 {} ms{}",
r.primes,
r.elapsed_ms,
if r.cancelled { "(被取消)" } else { "" }
));
self.done.update(|d| *d += 1);
}
} else if let Some(f) = data.downcast_ref::<TaskFailed>() {
self.report.set(format!("任务 {} 崩了(已收尾)", f.id));
}
}
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let rt = Runtime::new();
let mut app = App::new(rt.clone());
let vm = Rc::new(Demo {
report: Signal::new(&rt, "还没跑过任务".to_string()),
done: Signal::new(&rt, 0),
});
let _id = app.window_erased(
WindowConfig::new()
.title("lieui · 后台任务")
.size(560.0, 360.0),
lieui::app::erased(Rc::clone(&vm)),
);
app.run()
}