Working scrollbar

This commit is contained in:
Marco De Araujo 2026-01-10 11:19:19 -04:00
parent df1d1dddc6
commit 000e31a14f
4 changed files with 58 additions and 26 deletions

View file

@ -174,7 +174,6 @@ impl App {
} }
if area.len() <= 1 { if area.len() <= 1 {
let _formgen = area[0].height;
dbg!(area[0].height); dbg!(area[0].height);
return; return;
} }

View file

@ -9,7 +9,11 @@ use ratatui::{
use crate::i18n::t; use crate::i18n::t;
use chrono::Local; 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 now = Local::now();
let datatime_str = now.format("%Y-%m-%d %H:%M:%S").to_string(); let datatime_str = now.format("%Y-%m-%d %H:%M:%S").to_string();
let countdown_str = format!("{}s", seconds_until_update); let countdown_str = format!("{}s", seconds_until_update);

View file

@ -3,7 +3,7 @@ use std::cmp::min;
use crate::i18n::t; use crate::i18n::t;
use crate::ui::dashboard::{ use crate::ui::dashboard::{
MonitorStatus, MonitorViewState, MonitorStatus, MonitorViewState,
model::{DashboardViewState, GroupViewState, BORDER_LINES_VIEW}, model::{BORDER_LINES_VIEW, DashboardViewState, GroupViewState},
}; };
use ratatui::{ use ratatui::{
Frame, Frame,
@ -16,26 +16,51 @@ use ratatui::{
const STATUS_LINE_LENGTH: usize = 100; const STATUS_LINE_LENGTH: usize = 100;
const MAX_NAME_LENGTH: usize = 30; const MAX_NAME_LENGTH: usize = 30;
pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &DashboardViewState) { pub fn render_monitor_list(main_frame: &mut Frame, area: Rect, state: &mut DashboardViewState) {
let constraints: Vec<Constraint> = state let available_height = area.height as usize;
.groups let total_lenght = state.get_total_lenght();
.iter()
.map(|g| {
let height_neeed = BORDER_LINES_VIEW + g.monitors.len();
Constraint::Length(height_neeed as u16)
})
.collect();
if constraints.is_empty() { if (state.scroll_state.get_position() + available_height) > total_lenght {
return; 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() { for (i, group) in state.groups.iter().enumerate() {
if group_area.height > 0 { let group_height = group.monitors.len() + BORDER_LINES_VIEW;
render_group(main_frame, group_area, group, i == 0);
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;
} }
} }

View file

@ -37,7 +37,7 @@ pub struct DashboardViewState {
pub error_message: Option<String>, pub error_message: Option<String>,
pub auto_refresh_interval: u32, pub auto_refresh_interval: u32,
pub scroll_state: ScrollbarState, pub scroll_state: ScrollbarState,
content_length: usize, total_length: usize,
} }
impl DashboardViewState { impl DashboardViewState {
@ -50,7 +50,7 @@ impl DashboardViewState {
error_message: None, error_message: None,
auto_refresh_interval: 300, auto_refresh_interval: 300,
scroll_state: ScrollbarState::new(0), 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() .iter()
.map(|g| g.monitors.len() + BORDER_LINES_VIEW) .map(|g| g.monitors.len() + BORDER_LINES_VIEW)
.sum::<usize>(); .sum();
Self { Self {
title: data.title, title: data.title,
@ -76,17 +76,21 @@ impl DashboardViewState {
is_loading: false, is_loading: false,
error_message: None, error_message: None,
auto_refresh_interval: data.auto_refresh_interval.max(30), auto_refresh_interval: data.auto_refresh_interval.max(30),
scroll_state: ScrollbarState::new(content_length.saturating_sub(1)), scroll_state: ScrollbarState::new(total_length.saturating_sub(1)),
content_length, total_length,
} }
} }
pub fn get_total_lenght(&self) -> usize {
self.total_length
}
pub fn get_all_monitors(&self) -> Vec<&MonitorViewState> { pub fn get_all_monitors(&self) -> Vec<&MonitorViewState> {
self.groups.iter().flat_map(|g| g.monitors.iter()).collect() self.groups.iter().flat_map(|g| g.monitors.iter()).collect()
} }
pub fn show_vertical_scrollbar(&self, height: u16) -> bool { pub fn show_vertical_scrollbar(&self, available_height: u16) -> bool {
height < self.content_length as u16 self.total_length as u16 > available_height
} }
} }