cursive-async-view 0.8.0

A loading-screen wrapper for gyscos/cursive views
Documentation
extern crate cursive_async_view;

use std::sync::mpsc::channel;
use std::sync::mpsc::TryRecvError;
use std::thread;
use std::time::Duration;

use cursive::views::{Dialog, LinearLayout, RadioGroup};
use cursive::{Cursive, CursiveExt};
use cursive_async_view::{AsyncState, AsyncView};

fn main() {
    let mut siv = Cursive::default();

    // We can quit by pressing `q`
    siv.add_global_callback('q', Cursive::quit);

    // create channel to send radio buttons text over it
    let (tx, rx) = channel();

    // calculate the radio button contents in a different thread
    thread::spawn(move || {
        // Figuring out the radio button texts takes veeeeery long!
        // Glad we have the async view, entertaining the user until
        // all our figuring out is done!

        tx.send("πŸΆπŸ”” Ding dong, you are wrong...").unwrap();
        thread::sleep(Duration::from_secs(1));
        tx.send("πŸ¦†πŸ’¦ Splish splash, your opinion is trash!")
            .unwrap();
        thread::sleep(Duration::from_secs(1));
        tx.send("πŸ¦€πŸ›‘ Flippity flop, you need to stop").unwrap();
        thread::sleep(Duration::from_secs(1));
        tx.send("πŸ”«πŸΈ Hippity hoppity, this view is now my property")
            .unwrap();
        thread::sleep(Duration::from_secs(1));
        tx.send("πŸ¦„πŸš¬ Miss me").unwrap();
        thread::sleep(Duration::from_secs(1));
    });

    let mut group = RadioGroup::new(); // !Send struct

    // We can't use a LinearLayout here, 'cause it's not `Copy`. Further
    // explanation below.
    let mut buttons = Vec::new();
    let async_view = AsyncView::new(&mut siv, move || {
        // be quick or be dead
        match rx.try_recv() {
            // ooooooh, another radio button for me
            Ok(msg) => {
                buttons.push(group.button_str(msg));

                // there are more buttons to be excited about!
                AsyncState::Pending
            }

            // no button today, but maybe next time
            Err(TryRecvError::Empty) => AsyncState::Pending,

            // channel got closed, so looks like these are all my buttons...
            Err(TryRecvError::Disconnected) => {
                // If the channel has disconnected, we have received all radio
                // buttons, so lets resolve the async view.

                match buttons.len() {
                    0 => AsyncState::Error("Buttons could not be loaded".to_string()),
                    1 => AsyncState::Error("There is no choice!".to_string()),
                    _ => {
                        // ==> EXPLANATION <==
                        // We have to create the linear layout here, as it does
                        // not implement the copy trait. As we cannot move a
                        // captured variable out of an FnMut and cannot copy the
                        // linear layout, we have to create it inside the
                        // closure from the buttons vector.
                        let mut layout = LinearLayout::vertical();
                        for button in buttons.drain(..) {
                            layout.add_child(button);
                        }

                        AsyncState::Available(layout)
                    }
                }
            }
        }
    });

    // dialogs are cool, so let's use one!
    let dialog = Dialog::around(async_view.with_width(40)).button("Ok", |s| s.quit());
    siv.add_layer(dialog);

    // fox on the run!
    siv.run();
}