gled 2.6.2

gled is an application for creating animations and effects on artnet or wled light installations
use crate::storage::asset::project::scene_instance_path::SceneInstancePath;
use crossbeam_channel::{Receiver, Sender, unbounded};
use egui::mutex::Mutex;
use once_cell::sync::{Lazy, OnceCell};
use std::collections::HashSet;

static SENDER: OnceCell<Sender<MidiState>> = OnceCell::new();
static PREVIOUS_STATE: OnceCell<Mutex<MidiState>> = OnceCell::new();
static SENDERS: Lazy<Mutex<Vec<Sender<MidiState>>>> = Lazy::new(|| Mutex::new(Vec::new()));

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct MidiState {
    pub blackout: bool,
    pub beat_flank: u8,
    pub active_scenes: HashSet<SceneInstancePath>,
    pub available_scenes_a: usize,
    pub available_scenes_b: usize,
    pub available_scenes_c: usize,
}

impl MidiState {
    pub fn enqueue(self) {
        let mut previous = PREVIOUS_STATE
            .get_or_init(|| Mutex::new(self.clone()))
            .lock();
        if *previous == self {
            return;
        }
        *previous = self.clone();
        SENDER
            .get()
            .expect("Could not get sender")
            .send(self)
            .expect("Could not send state");
    }
}

pub fn start() {
    let (sender, receiver) = unbounded();
    SENDER.set(sender).expect("Could not set sender");

    loop {
        let state = receiver.recv().expect("Could not receive state");
        SENDERS
            .lock()
            .retain(|sender| sender.send(state.clone()).is_ok());
    }
}

pub fn new_receiver() -> Receiver<MidiState> {
    let (sender, receiver) = unbounded();
    SENDERS.lock().push(sender);
    receiver
}