egui_async/egui/widgets/
refresh_button.rs1use crate::bind::{Bind, MaybeSend};
4
5#[must_use = "You should call .show() on this widget to render it"]
7pub struct RefreshButton<'a, T, E> {
8 bind: &'a mut Bind<T, E>,
9 interval_secs: f64,
10 debounce_factor: f64,
11 text: String,
12}
13
14impl<'a, T, E> RefreshButton<'a, T, E> {
15 pub fn new(bind: &'a mut Bind<T, E>) -> Self {
17 Self {
18 bind,
19 interval_secs: 60.0,
20 debounce_factor: 4.0,
21 text: "🔄".to_string(),
22 }
23 }
24
25 pub const fn interval_secs(mut self, secs: f64) -> Self {
27 self.interval_secs = secs;
28 self
29 }
30
31 pub fn show<Fut>(self, ui: &mut egui::Ui, f: impl FnOnce() -> Fut) -> egui::Response
33 where
34 Fut: Future<Output = Result<T, E>> + MaybeSend + 'static,
35 T: MaybeSend + 'static,
36 E: MaybeSend + 'static,
37 {
38 let is_pending = self.bind.is_pending();
39 let resp = ui.add_enabled(!is_pending, egui::Button::new(self.text));
40
41 let diff = if self.bind.since_completed() > self.interval_secs / self.debounce_factor
43 && resp.clicked()
44 && !is_pending
45 {
46 self.bind.refresh(f());
47 -1.0
48 } else {
49 self.bind.request_every_sec(f, self.interval_secs)
50 };
51
52 let hover_text = if is_pending {
53 "Refreshing...".to_string()
54 } else if diff < 0.0 {
55 "Refreshing now!".to_string()
56 } else {
57 format!("Refreshing automatically in {diff:.0}s...")
58 };
59
60 resp.on_hover_text(hover_text)
61 }
62}