Feature 3: relative due dates right-aligned in task list
- Replace absolute date with relative string (Overdue, Xh left, X days left) - Overdue in Red, <24h in Yellow, >=24h in DarkGray - Due string right-aligned via padding calculation
This commit is contained in:
+34
-10
@@ -49,6 +49,24 @@ pub fn render_tabs_bar(
|
||||
frame.render_widget(tabs, area);
|
||||
}
|
||||
|
||||
fn relative_due_str(due: chrono::NaiveDateTime) -> (String, Color) {
|
||||
let now = chrono::Local::now().naive_local();
|
||||
let diff = due - now;
|
||||
|
||||
if diff < chrono::Duration::zero() {
|
||||
(" Overdue ".to_string(), Color::Red)
|
||||
} else if diff < chrono::Duration::hours(24) {
|
||||
let hours = diff.num_hours();
|
||||
(format!(" {}h left ", hours), Color::Yellow)
|
||||
} else {
|
||||
let days = diff.num_days();
|
||||
(
|
||||
format!(" {} day{} left ", days, if days == 1 { "" } else { "s" }),
|
||||
Color::DarkGray,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_task_list(
|
||||
frame: &mut Frame,
|
||||
area: Rect,
|
||||
@@ -61,6 +79,8 @@ pub fn render_task_list(
|
||||
let done = tasks.iter().filter(|t| t.status == TaskStatus::Completed).count();
|
||||
let todo = total - done;
|
||||
|
||||
let content_width = (area.width as usize).saturating_sub(5);
|
||||
|
||||
let items: Vec<ListItem> = tasks
|
||||
.iter()
|
||||
.map(|task| {
|
||||
@@ -69,12 +89,12 @@ pub fn render_task_list(
|
||||
TaskStatus::NeedsAction => "[ ]",
|
||||
};
|
||||
|
||||
let due_str = task
|
||||
let (due_text, due_color) = task
|
||||
.due
|
||||
.map(|d| d.format(" %d/%m/%Y %H:%M").to_string())
|
||||
.unwrap_or_default();
|
||||
.map(relative_due_str)
|
||||
.unwrap_or((String::new(), Color::DarkGray));
|
||||
|
||||
let content = Line::from(vec![
|
||||
let mut spans = vec![
|
||||
Span::styled(
|
||||
format!("{} ", checkbox),
|
||||
Style::default().fg(if task.status == TaskStatus::Completed {
|
||||
@@ -93,12 +113,16 @@ pub fn render_task_list(
|
||||
},
|
||||
),
|
||||
),
|
||||
Span::styled(
|
||||
due_str,
|
||||
Style::default().fg(Color::DarkGray),
|
||||
),
|
||||
]);
|
||||
ListItem::new(content)
|
||||
];
|
||||
|
||||
if !due_text.is_empty() {
|
||||
let left_len: usize = spans.iter().map(|s| s.content.len()).sum();
|
||||
let pad = content_width.saturating_sub(left_len + due_text.len());
|
||||
spans.push(Span::raw(" ".repeat(pad)));
|
||||
spans.push(Span::styled(due_text, Style::default().fg(due_color)));
|
||||
}
|
||||
|
||||
ListItem::new(Line::from(spans))
|
||||
})
|
||||
.collect();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user