liftof_tui/tabs/
tab_home.rs1use std::collections::{
4 HashMap,
5 VecDeque,
6};
7
8use std::time::{
9 Instant,
10 };
12
13use std::sync::{
14 Arc,
15 Mutex,
16};
17use ratatui::prelude::*;
18
19use ratatui::Frame;
21use ratatui::layout::Rect;
22use ratatui::widgets::{
23 Block,
24 BorderType,
25 Borders,
26 Paragraph,
27 Table,
28 Row,
29};
30
31use gondola_core::prelude::LIFTOF_LOGO_SHOW;
33
34use crate::colors::ColorTheme;
35
36
37#[derive(Debug, Clone)]
38pub struct HomeTab<'a> {
39 pub theme : ColorTheme,
40 pub streamer : Arc<Mutex<VecDeque<String>>>,
41 pub pack_stat : Arc<Mutex<HashMap<&'a str, usize>>>,
42 pub stream : String,
43 pub stream_max : usize,
44 start_time : Instant,
45}
46
47impl HomeTab<'_> {
48 pub fn new(theme : ColorTheme,
49 streamer : Arc<Mutex<VecDeque<String>>>,
50 pack_stat : Arc<Mutex<HashMap<&str,usize>>>) -> HomeTab {
51 HomeTab {
52 theme,
53 streamer,
54 pack_stat,
55 stream : String::from(""),
56 stream_max : 30,
57 start_time : Instant::now(),
58 }
59 }
60
61 pub fn render(&mut self, main_window : &Rect, frame : &mut Frame) {
62 let main_chunks = Layout::default()
63 .direction(Direction::Vertical)
64 .constraints(
65 [Constraint::Percentage(70),
66 Constraint::Percentage(30)].as_ref(),
67 )
68 .split(*main_window);
69
70 let upper_chunks = Layout::default()
71 .direction(Direction::Horizontal)
72 .constraints(
73 [Constraint::Percentage(70),
74 Constraint::Percentage(30)].as_ref(),
75 )
76 .split(main_chunks[0]);
77
78 let mut rows = Vec::<Row>::new();
79 let mut sum_pack = 0;
80 let passed_time = self.start_time.elapsed().as_secs_f64();
81 match self.pack_stat.lock() {
82 Err(_err) => (),
83 Ok(mut _stat) => {
84 for k in _stat.keys() {
85 if _stat[k] != 0 {
87 sum_pack += _stat[k];
88 if k.contains("Heart"){
89 rows.push(Row::new(vec![format!(" \u{1f493} {:.1}", _stat[k]),
90 format!("{:.1}", (_stat[k] as f64)/passed_time,),
91 format!("[{}]", k)]));
92 } else {
93 rows.push(Row::new(vec![format!(" \u{279f} {:.1}", _stat[k]),
94 format!("{:.1}", (_stat[k] as f64)/passed_time,),
95 format!("[{}]", k)]));
96 }
97 }
98 }
99 }
100 }
101 rows.push(Row::new(vec![" \u{FE4C}\u{FE4C}\u{FE4C}","\u{FE4C}\u{FE4C}","\u{FE4C}\u{FE4C}\u{FE4C}\u{FE4C}\u{FE4C}\u{FE4C}"]));
102 rows.push(Row::new(vec![format!(" \u{279f}{}", sum_pack),
103 format!("{:.1}/s", (sum_pack as f64)/passed_time),
104 format!("[TOTAL]")]));
105
106 let widths = [Constraint::Percentage(30),
107 Constraint::Percentage(20),
108 Constraint::Percentage(50)];
109 let table = Table::new(rows, widths)
110 .column_spacing(1)
111 .header(
112 Row::new(vec![" N", "\u{1f4e6}/s", "Type"])
113 .bottom_margin(1)
114 .top_margin(1)
115 .style(Style::new().add_modifier(Modifier::UNDERLINED))
116 )
117 .block(Block::new()
118 .title("Packet summary \u{1f4e6}")
119 .borders(Borders::ALL)
120 .border_type(BorderType::Rounded)
121 )
122 .style(self.theme.style());
123
124 let main_view = Paragraph::new(LIFTOF_LOGO_SHOW)
125 .style(self.theme.style())
126 .alignment(Alignment::Center)
127 .block(
128 Block::default()
129 .borders(Borders::NONE)
130 );
131
132 match self.streamer.lock() {
133 Err(_err) => (),
134 Ok(mut _vecdeque) => {
135 self.stream = _vecdeque
136 .iter()
137 .cloned() .collect::<Vec<String>>()
139 .join("\n");
140 while _vecdeque.len() > self.stream_max {
142 _vecdeque.pop_front();
143 }
144 },
145 }
146 let side_view = Paragraph::new(self.stream.clone())
148 .style(self.theme.style())
149 .alignment(Alignment::Left)
150 .block(
151 Block::default()
152 .borders(Borders::ALL)
153 .border_type(BorderType::Rounded)
154 .title("Stream")
155 );
156 frame.render_widget(main_view, upper_chunks[0]);
157 frame.render_widget(side_view, main_chunks[1]);
158 frame.render_widget(table, upper_chunks[1])
159 }
160}
161