mecomp_tui/state/view.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
//! The `ViewStore` is responsible for managing the `CurrentView` to be displayed.
use tokio::sync::{
broadcast,
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
};
use crate::{termination::Interrupted, ui::components::content_view::ActiveView};
/// The `ViewStore` is responsible for managing the `CurrentView` to be displayed.
#[allow(clippy::module_name_repetitions)]
pub struct ViewState {
state_tx: UnboundedSender<ActiveView>,
}
impl ViewState {
/// Create a new `ViewStore`.
#[must_use]
pub fn new() -> (Self, UnboundedReceiver<ActiveView>) {
let (state_tx, state_rx) = unbounded_channel::<ActiveView>();
(Self { state_tx }, state_rx)
}
/// A loop that updates the store when requested
///
/// # Errors
///
/// Fails if the state cannot be sent
pub async fn main_loop(
&self,
mut action_rx: UnboundedReceiver<ActiveView>,
mut interrupt_rx: broadcast::Receiver<Interrupted>,
) -> anyhow::Result<Interrupted> {
let mut state = ActiveView::default();
// the initial state once
self.state_tx.send(state)?;
let result = loop {
tokio::select! {
// Handle the actions coming from the UI
// and process them to do async operations
Some(action) = action_rx.recv() => {
state = action;
self.state_tx.send(state)?;
},
// Catch and handle interrupt signal to gracefully shutdown
Ok(interrupted) = interrupt_rx.recv() => {
break interrupted;
}
}
};
Ok(result)
}
}