mecomp_tui/state/
popup.rs1use tokio::sync::{
5 broadcast,
6 mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
7};
8
9use crate::{state::action::PopupAction, termination::Interrupted, ui::widgets::popups::PopupType};
10
11#[derive(Debug, Clone)]
13#[allow(clippy::module_name_repetitions)]
14pub struct PopupState {
15 state_tx: UnboundedSender<Option<PopupType>>,
16}
17
18#[allow(clippy::module_name_repetitions)]
19pub type PopupStateReceiver = UnboundedReceiver<Option<PopupType>>;
20
21impl PopupState {
22 #[must_use]
24 pub fn new() -> (Self, PopupStateReceiver) {
25 let (state_tx, state_rx) = unbounded_channel::<Option<PopupType>>();
26
27 (Self { state_tx }, state_rx)
28 }
29
30 pub async fn main_loop(
36 &self,
37 mut action_rx: UnboundedReceiver<PopupAction>,
38 mut interrupt_rx: broadcast::Receiver<Interrupted>,
39 ) -> anyhow::Result<Interrupted> {
40 self.state_tx.send(None)?;
42
43 let mut stack = Vec::new();
45
46 let result = loop {
47 tokio::select! {
48 Some(action) = action_rx.recv() => {
51 match action {
52 PopupAction::Open(popup) => {
53 stack.push(popup.clone());
54 }
55 PopupAction::Close => {
56 stack.pop();
57 }
58 }
59 self.state_tx.send(stack.last().cloned())?;
60 }
61 Ok(interrupted) = interrupt_rx.recv() => {
63 break interrupted;
64 }
65 }
66 };
67
68 Ok(result)
69 }
70}