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
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
use freya_core::prelude::{
    get_node_state,
    FreyaDOM,
    NodeState,
};
use freya_native_core::{
    prelude::{
        NodeId,
        NodeImmutable,
    },
    tags::TagName,
};
use tokio::sync::watch;
use torin::prelude::LayoutNode;

pub type DevtoolsReceiver = watch::Receiver<Vec<NodeInfo>>;

#[derive(Clone)]
pub struct Devtools {
    sender: watch::Sender<Vec<NodeInfo>>,
}

impl Devtools {
    pub fn new() -> (Self, DevtoolsReceiver) {
        let (sender, receiver) = watch::channel(Vec::new());

        (Self { sender }, receiver)
    }

    pub fn update(&self, fdom: &FreyaDOM) {
        let rdom = fdom.rdom();
        let layout = fdom.layout();

        let mut new_nodes = Vec::new();

        let mut root_found = false;
        let mut devtools_found = false;

        rdom.traverse_depth_first(|node| {
            let height = node.height();
            if height == 3 {
                if !root_found {
                    root_found = true;
                } else {
                    devtools_found = true;
                }
            }

            if !devtools_found && root_found {
                let has_layout = layout.get(node.id()).is_some();
                if has_layout {
                    let node_type = node.node_type();
                    new_nodes.push(NodeInfo {
                        id: node.id(),
                        parent_id: node.parent_id(),
                        children_len: node
                            .children()
                            .iter()
                            .filter(|node| layout.get(node.id()).is_some())
                            .count(),
                        tag: *node_type.tag().unwrap(),
                        height: node.height(),
                        state: get_node_state(&node),
                        layout_node: layout.get(node.id()).unwrap().clone(),
                    });
                }
            }
        });

        self.sender
            .send(new_nodes)
            .expect("Failed to sync the Devtools.");
    }
}

#[derive(Clone, PartialEq)]
pub struct NodeInfo {
    pub id: NodeId,
    pub parent_id: Option<NodeId>,
    pub children_len: usize,
    pub tag: TagName,
    pub height: u16,
    pub state: NodeState,
    pub layout_node: LayoutNode,
}