egui_pull_to_refresh 0.11.0

A pull to refresh library for egui
Documentation
use std::sync::{Arc, Mutex};
use std::thread;
use std::thread::sleep;

use eframe::{egui, NativeOptions};
use egui::{CentralPanel, ScrollArea};

use egui_pull_to_refresh::PullToRefresh;

#[derive(Debug, Clone)]
struct State {
    count: usize,
    loading: bool,
}

pub fn main() -> eframe::Result<()> {
    let state = Arc::new(Mutex::new(State {
        count: 0,
        loading: false,
    }));

    let mut slider_value = 0.0;

    eframe::run_ui_native(
        "Pull to refresh minimal example",
        NativeOptions::default(),
        move |ui, _frame| {
            CentralPanel::default().show_inside(ui, |ui| {
                // Disable text selection, so it doesn't interfere with the drag gesture
                ui.style_mut().interaction.selectable_labels = false;
                ui.style_mut().interaction.multi_widget_text_select = false;
                let current_state = state.lock().unwrap().clone();

                let response = PullToRefresh::new(current_state.loading).scroll_area_ui(ui, |ui| {
                    ScrollArea::vertical().show(ui, |ui| {
                        ui.set_width(ui.available_width());

                        ui.heading("Pull to refresh demo");
                        ui.label("It doesn't conflict with sliders!");
                        ui.add(egui::Slider::new(&mut slider_value, 0.0..=100.0).text("value"));

                        ui.label("And works with scroll areas!");
                        let count = current_state.count;
                        for i in count..count + 100 {
                            ui.label(format!("Hello {i}"));
                        }
                    })
                });

                if response.should_refresh() {
                    state.lock().unwrap().loading = true;
                    let state = state.clone();
                    thread::spawn(move || {
                        sleep(std::time::Duration::from_secs(1));
                        let mut state = state.lock().unwrap();
                        state.count += 100;
                        state.loading = false;
                    });
                }
            });
        },
    )
}