use std::collections::HashMap;
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::Style;
use ratatui::text::Line;
use ratatui::widgets::{Block, Borders, Paragraph, Widget, Wrap};
use bears::task::Task;
use super::super::style::Theme;
use super::body::BodyWidget;
use super::dep_tree::{DepTreeWidget, SubtaskGraphWidget};
use super::task_info::TaskInfoWidget;
pub(in crate::tui) struct DetailMetrics {
pub content_height: u16,
pub visible_height: u16,
}
pub(in crate::tui) struct TaskDetailWidget<'a> {
task: Option<&'a Task>,
task_map: &'a HashMap<String, Task>,
scroll: u16,
border_style: Style,
metrics: &'a mut DetailMetrics,
theme: &'a Theme,
}
impl<'a> TaskDetailWidget<'a> {
pub fn new(
task: Option<&'a Task>,
task_map: &'a HashMap<String, Task>,
scroll: u16,
border_style: Style,
metrics: &'a mut DetailMetrics,
theme: &'a Theme,
) -> Self {
Self {
task,
task_map,
scroll,
border_style,
metrics,
theme,
}
}
}
impl TaskDetailWidget<'_> {
pub fn render(self, area: Rect, buf: &mut Buffer) {
let block = Block::default()
.title(" Detail ")
.borders(Borders::ALL)
.border_style(self.border_style);
let Some(task) = self.task else {
Paragraph::new("No tasks found.")
.block(block)
.render(area, buf);
self.metrics.content_height = 0;
self.metrics.visible_height = area.height.saturating_sub(2);
return;
};
let mut lines: Vec<Line> = Vec::new();
lines.extend(TaskInfoWidget::new(task, self.task_map, self.theme).lines());
lines.extend(DepTreeWidget::new(task, self.task_map, self.theme).lines());
lines.extend(SubtaskGraphWidget::new(task, self.task_map, self.theme).lines());
lines.extend(BodyWidget::new(&task.body, self.theme).lines());
let inner_width = area.width.saturating_sub(2) as usize;
let content_height = if inner_width == 0 {
lines.len() as u16
} else {
lines
.iter()
.map(|line| {
let w = line.width();
if w <= inner_width {
1u16
} else {
(w as u16).div_ceil(inner_width as u16)
}
})
.sum()
};
let visible_height = area.height.saturating_sub(2);
self.metrics.content_height = content_height;
self.metrics.visible_height = visible_height;
Paragraph::new(lines)
.block(block)
.wrap(Wrap { trim: false })
.scroll((self.scroll, 0))
.render(area, buf);
}
}