diff --git a/src/ui/app.rs b/src/ui/app.rs index 4d2dbca..96e2e2d 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -174,7 +174,6 @@ impl App { } if area.len() <= 1 { - let _formgen = area[0].height; dbg!(area[0].height); return; } diff --git a/src/ui/components/footer.rs b/src/ui/components/footer.rs index 806002b..9a79434 100644 --- a/src/ui/components/footer.rs +++ b/src/ui/components/footer.rs @@ -9,7 +9,11 @@ use ratatui::{ use crate::i18n::t; use chrono::Local; -pub fn render_footer(frame: &mut Frame, area: Rect, seconds_until_update: u64) { +pub fn render_footer( + frame: &mut Frame, + area: Rect, + seconds_until_update: u64 +) { let now = Local::now(); let datatime_str = now.format("%Y-%m-%d %H:%M:%S").to_string(); let countdown_str = format!("↻ {}s", seconds_until_update); diff --git a/src/ui/components/monitor_list.rs b/src/ui/components/monitor_list.rs index 0fc4256..df9f28c 100644 --- a/src/ui/components/monitor_list.rs +++ b/src/ui/components/monitor_list.rs @@ -3,7 +3,7 @@ use std::cmp::min; use crate::i18n::t; use crate::ui::dashboard::{ MonitorStatus, MonitorViewState, - model::{DashboardViewState, GroupViewState, BORDER_LINES_VIEW}, + model::{BORDER_LINES_VIEW, DashboardViewState, GroupViewState}, }; use ratatui::{ Frame, @@ -16,26 +16,51 @@ use ratatui::{ const STATUS_LINE_LENGTH: usize = 100; const MAX_NAME_LENGTH: usize = 30; -pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &DashboardViewState) { - let constraints: Vec = state - .groups - .iter() - .map(|g| { - let height_neeed = BORDER_LINES_VIEW + g.monitors.len(); - Constraint::Length(height_neeed as u16) - }) - .collect(); +pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut DashboardViewState) { + let available_height = area.height as usize; + let total_lenght = state.get_total_lenght(); - if constraints.is_empty() { - return; + if (state.scroll_state.get_position() + available_height) > total_lenght { + state.scroll_state = state.scroll_state.position(total_lenght - available_height); } - let group_areas = Layout::vertical(constraints).split(area); + let scroll_pos = state.scroll_state.get_position(); + let mut current_y = area.y as usize; + let mut rendered_height = 0; + let mut lines_skipped = 0; - for (i, (group, &group_area)) in state.groups.iter().zip(group_areas.iter()).enumerate() { - if group_area.height > 0 { - render_group(main_frame, group_area, group, i == 0); + for (i, group) in state.groups.iter().enumerate() { + let group_height = group.monitors.len() + BORDER_LINES_VIEW; + + if lines_skipped + group_height <= scroll_pos { + lines_skipped += group_height; + continue; } + + let visible_height = if lines_skipped < scroll_pos { + group_height - (scroll_pos - lines_skipped) + } else { + group_height + } + .min(available_height - rendered_height); + + let group_area = Rect { + x: area.x, + y: current_y as u16, + width: area.width, + height: visible_height as u16, + }; + + render_group( + main_frame, + group_area, + group, + i == 0 && lines_skipped >= scroll_pos, + ); + + current_y += visible_height; + rendered_height += visible_height; + lines_skipped += group_height; } } diff --git a/src/ui/dashboard/model.rs b/src/ui/dashboard/model.rs index a375ed9..1d689e0 100644 --- a/src/ui/dashboard/model.rs +++ b/src/ui/dashboard/model.rs @@ -37,7 +37,7 @@ pub struct DashboardViewState { pub error_message: Option, pub auto_refresh_interval: u32, pub scroll_state: ScrollbarState, - content_length: usize, + total_length: usize, } impl DashboardViewState { @@ -50,7 +50,7 @@ impl DashboardViewState { error_message: None, auto_refresh_interval: 300, scroll_state: ScrollbarState::new(0), - content_length: 0, + total_length: 0, } } @@ -64,10 +64,10 @@ impl DashboardViewState { }); } - let content_length = groups + let total_length: usize = groups .iter() .map(|g| g.monitors.len() + BORDER_LINES_VIEW) - .sum::(); + .sum(); Self { title: data.title, @@ -76,17 +76,21 @@ impl DashboardViewState { is_loading: false, error_message: None, auto_refresh_interval: data.auto_refresh_interval.max(30), - scroll_state: ScrollbarState::new(content_length.saturating_sub(1)), - content_length, + scroll_state: ScrollbarState::new(total_length.saturating_sub(1)), + total_length, } } + pub fn get_total_lenght(&self) -> usize { + self.total_length + } + pub fn get_all_monitors(&self) -> Vec<&MonitorViewState> { self.groups.iter().flat_map(|g| g.monitors.iter()).collect() } - pub fn show_vertical_scrollbar(&self, height: u16) -> bool { - height < self.content_length as u16 + pub fn show_vertical_scrollbar(&self, available_height: u16) -> bool { + self.total_length as u16 > available_height } }