gled-ui 2.34.0

gled's egui interface, shared by the desktop app and the browser
Documentation
use super::App;
use egui::ViewportId;

impl App {
    /// A red bar while the connection to a remote engine is interrupted, with
    /// the time since the last contact.
    pub(super) fn connection_banner(&self, ui: &mut egui::Ui, viewport_id: Option<ViewportId>) {
        if !self.connection.is_remote() {
            return;
        }
        // Silence is only noticed when the interface looks again.
        ui.ctx()
            .request_repaint_after(web_time::Duration::from_secs(1));
        let Some(interruption) = self.connection.interruption() else {
            return;
        };
        egui::Panel::top(format!("{viewport_id:?} connection"))
            .frame(
                egui::Frame::new()
                    .fill(egui::Color32::DARK_RED)
                    .inner_margin(egui::Margin::same(4)),
            )
            .show(ui, |ui| {
                ui.vertical_centered(|ui| {
                    ui.colored_label(
                        egui::Color32::WHITE,
                        format!(
                            "Connection to the engine interrupted, last contact {} ago. \
                             Reconnecting…",
                            elapsed(interruption.last_contact)
                        ),
                    );
                });
            });
    }
}

/// A duration as people say it: `45s`, `6m20s`, `2h5m`.
fn elapsed(duration: web_time::Duration) -> String {
    let seconds = duration.as_secs();
    match seconds {
        0..60 => format!("{seconds}s"),
        60..3600 => format!("{}m{}s", seconds / 60, seconds % 60),
        _ => format!("{}h{}m", seconds / 3600, seconds % 3600 / 60),
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn elapsed_time_reads_like_speech() {
        assert_eq!(elapsed(web_time::Duration::from_secs(45)), "45s");
        assert_eq!(elapsed(web_time::Duration::from_secs(380)), "6m20s");
        assert_eq!(elapsed(web_time::Duration::from_secs(7500)), "2h5m");
    }
}