Skip to content

Commit 2391d55

Browse files
author
ComputelessComputer
committed
add checklist priorities, chat box mode colors, fix kanban date display, fix @ navigation, show full gcal event details
1 parent cda01ce commit 2391d55

3 files changed

Lines changed: 101 additions & 29 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aipm"
3-
version = "0.9.0"
3+
version = "0.9.1"
44
edition = "2021"
55

66
[dependencies]

src/google.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ impl GoogleToken {
3636

3737
#[derive(Debug, Clone)]
3838
pub struct CalendarEvent {
39-
pub id: String,
39+
pub _id: String,
4040
pub title: String,
4141
pub start_date: String,
4242
pub end_date: String,
@@ -291,7 +291,7 @@ pub fn get_upcoming_events(token: &str, days: u32) -> Result<Vec<CalendarEvent>,
291291
let end = &item["end"];
292292
let all_day = start["date"].is_string();
293293
CalendarEvent {
294-
id: item["id"].as_str().unwrap_or("").to_string(),
294+
_id: item["id"].as_str().unwrap_or("").to_string(),
295295
title: item["summary"].as_str().unwrap_or("(No title)").to_string(),
296296
start_date: start["dateTime"]
297297
.as_str()

src/main.rs

Lines changed: 98 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use std::io::{self, Stdout, Write};
99
use std::sync::mpsc;
1010
use std::time::{Duration, Instant};
1111

12-
use chrono::{Datelike, Utc};
12+
use chrono::{Datelike, Local, Utc};
1313
use crossterm::{
1414
cursor::{Hide, MoveTo, Show},
1515
event::{
@@ -877,7 +877,7 @@ fn handle_key(app: &mut App, key: KeyEvent) -> io::Result<bool> {
877877
let bp = char_byte_pos(&app.input, app.input_cursor);
878878
app.input.insert_str(bp, &tag);
879879
app.input_cursor += tag.chars().count();
880-
app.tab = Tab::Default;
880+
app.input_mode = InputMode::Chat;
881881
app.focus = Focus::Input;
882882
return Ok(false);
883883
}
@@ -4728,10 +4728,14 @@ fn render_input_bar(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) -> io:
47284728
let y_help = rows.saturating_sub(1);
47294729

47304730
let sep = "─".repeat(content_width);
4731+
let mode_color = match app.input_mode {
4732+
InputMode::Chat => Color::DarkGrey,
4733+
InputMode::Add => Color::Green,
4734+
};
47314735
queue!(
47324736
stdout,
47334737
MoveTo(x, y_sep_top),
4734-
SetForegroundColor(Color::DarkGrey),
4738+
SetForegroundColor(mode_color),
47354739
Print(&sep),
47364740
ResetColor
47374741
)?;
@@ -4749,12 +4753,15 @@ fn render_input_bar(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) -> io:
47494753

47504754
queue!(stdout, MoveTo(x, y_input))?;
47514755
match app.focus {
4752-
Focus::Input => queue!(stdout, ResetColor)?,
4756+
Focus::Input => queue!(stdout, SetForegroundColor(mode_color))?,
47534757
Focus::Tabs | Focus::Board | Focus::Edit => {
47544758
queue!(stdout, SetForegroundColor(Color::DarkGrey))?
47554759
}
47564760
};
47574761
queue!(stdout, Print(prompt))?;
4762+
if app.focus == Focus::Input {
4763+
queue!(stdout, ResetColor)?;
4764+
}
47584765

47594766
if shown.is_empty() {
47604767
let placeholder = match app.input_mode {
@@ -4774,7 +4781,7 @@ fn render_input_bar(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) -> io:
47744781
queue!(
47754782
stdout,
47764783
MoveTo(x, y_sep_bottom),
4777-
SetForegroundColor(Color::DarkGrey),
4784+
SetForegroundColor(mode_color),
47784785
Print(&sep),
47794786
ResetColor
47804787
)?;
@@ -5094,7 +5101,15 @@ fn render_calendar_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
50945101
if y_cur >= y_start + available_rows as u16 {
50955102
break;
50965103
}
5097-
let entry = format!("{} • {} [{}]", evt.start_date, evt.title, evt.calendar_name);
5104+
let time_str = if evt.all_day {
5105+
"All day".to_string()
5106+
} else {
5107+
format!("{} \u{2013} {}", evt.start_date, evt.end_date)
5108+
};
5109+
let entry = format!(
5110+
"{} \u{2022} {} [{}]",
5111+
time_str, evt.title, evt.calendar_name
5112+
);
50985113
queue!(
50995114
stdout,
51005115
MoveTo(events_x, y_cur),
@@ -5103,6 +5118,31 @@ fn render_calendar_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
51035118
ResetColor
51045119
)?;
51055120
y_cur += 1;
5121+
if let Some(loc) = &evt.location {
5122+
if !loc.is_empty() && y_cur < y_start + available_rows as u16 {
5123+
queue!(
5124+
stdout,
5125+
MoveTo(events_x, y_cur),
5126+
SetForegroundColor(Color::DarkGrey),
5127+
Print(clamp_text(&format!(" @ {}", loc), events_width)),
5128+
ResetColor
5129+
)?;
5130+
y_cur += 1;
5131+
}
5132+
}
5133+
if let Some(notes) = &evt.notes {
5134+
if !notes.is_empty() && y_cur < y_start + available_rows as u16 {
5135+
let note_line = format!(" {}", notes.lines().next().unwrap_or_default());
5136+
queue!(
5137+
stdout,
5138+
MoveTo(events_x, y_cur),
5139+
SetForegroundColor(Color::DarkGrey),
5140+
Print(clamp_text(&note_line, events_width)),
5141+
ResetColor
5142+
)?;
5143+
y_cur += 1;
5144+
}
5145+
}
51065146
}
51075147
y_cur += 1;
51085148
} else if app.calendar_loading {
@@ -5224,6 +5264,7 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
52245264

52255265
let due_col_w = 12usize;
52265266
let bucket_col_w = 14usize;
5267+
let pri_col_w = 5usize;
52275268

52285269
for (draw_i, &(task_idx, is_child)) in ordered.iter().enumerate().skip(scroll).take(list_height)
52295270
{
@@ -5254,11 +5295,26 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
52545295
.unwrap_or_else(|| "—".to_string());
52555296
let due_display = clamp_text(&due_str, due_col_w);
52565297
let bucket_display = clamp_text(&task.bucket, bucket_col_w);
5298+
let pri_str = match task.priority {
5299+
Priority::Low => "Low",
5300+
Priority::Medium => "Med",
5301+
Priority::High => "High",
5302+
Priority::Critical => "Crit",
5303+
};
5304+
let pri_display = clamp_text(pri_str, pri_col_w);
52575305

52585306
let short_id = task.id.to_string().chars().take(8).collect::<String>();
52595307
let id_col_w = 9;
5260-
let fixed_cols =
5261-
expand_icon.width() + checkbox.len() + 1 + id_col_w + 2 + due_col_w + 2 + bucket_col_w;
5308+
let fixed_cols = expand_icon.width()
5309+
+ checkbox.len()
5310+
+ 1
5311+
+ id_col_w
5312+
+ 2
5313+
+ due_col_w
5314+
+ 2
5315+
+ bucket_col_w
5316+
+ 2
5317+
+ pri_col_w;
52625318
let title_max = content_width.saturating_sub(fixed_cols + 1);
52635319
let title = clamp_text(&task.title, title_max);
52645320
let title_pad = title_max.saturating_sub(title.width());
@@ -5267,7 +5323,7 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
52675323
queue!(stdout, MoveTo(x, y))?;
52685324
if is_sel && app.focus == Focus::Board {
52695325
let line = format!(
5270-
"{}{} {} {}{}{}{}{}{}",
5326+
"{}{} {} {}{}{}{}{}{}{}{}",
52715327
expand_icon,
52725328
checkbox,
52735329
short_id,
@@ -5277,6 +5333,8 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
52775333
due_display,
52785334
" ".repeat(due_pad.saturating_sub(0) + 2),
52795335
bucket_display,
5336+
" ",
5337+
pri_display,
52805338
);
52815339
queue!(
52825340
stdout,
@@ -5291,19 +5349,6 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
52915349
} else {
52925350
let prefix = format!("{}{} ", expand_icon, checkbox);
52935351
let id_str = format!("{} ", short_id);
5294-
let rest = format!(
5295-
"{}{}{}{}{}{}",
5296-
title,
5297-
" ".repeat(title_pad),
5298-
" ",
5299-
due_display,
5300-
" ".repeat(due_pad.saturating_sub(0) + 2),
5301-
bucket_display,
5302-
);
5303-
let rest_padded = pad_to_width(
5304-
&rest,
5305-
content_width.saturating_sub(prefix.width() + id_str.width()),
5306-
);
53075352
let status_color = if task.progress == Progress::Done {
53085353
Color::DarkGrey
53095354
} else {
@@ -5315,6 +5360,25 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
53155360
Progress::Done => Color::Green,
53165361
}
53175362
};
5363+
let rest_text = format!(
5364+
"{}{}{}{}{}{}",
5365+
title,
5366+
" ".repeat(title_pad),
5367+
" ",
5368+
due_display,
5369+
" ".repeat(due_pad.saturating_sub(0) + 2),
5370+
bucket_display,
5371+
);
5372+
let pri_color = match task.priority {
5373+
Priority::Critical => Color::Red,
5374+
Priority::High => Color::Yellow,
5375+
Priority::Medium => Color::White,
5376+
Priority::Low => Color::DarkGrey,
5377+
};
5378+
let rest_padded = pad_to_width(
5379+
&rest_text,
5380+
content_width.saturating_sub(prefix.width() + id_str.width() + 2 + pri_col_w),
5381+
);
53185382
queue!(
53195383
stdout,
53205384
SetForegroundColor(status_color),
@@ -5323,6 +5387,8 @@ fn render_checklist_tab(stdout: &mut Stdout, app: &App, cols: u16, rows: u16) ->
53235387
Print(&id_str),
53245388
SetForegroundColor(status_color),
53255389
Print(&rest_padded),
5390+
SetForegroundColor(pri_color),
5391+
Print(format!(" {}", pri_display)),
53265392
ResetColor
53275393
)?;
53285394
}
@@ -5795,7 +5861,7 @@ fn render_bucket_column(
57955861
}
57965862

57975863
fn render_timeline_tab(stdout: &mut Stdout, app: &mut App, cols: u16, rows: u16) -> io::Result<()> {
5798-
use chrono::{Datelike, Duration as ChronoDuration, Local};
5864+
use chrono::Duration as ChronoDuration;
57995865

58005866
let width = cols as usize;
58015867
let (x_margin, _gap) = choose_layout(width, 1);
@@ -6181,7 +6247,7 @@ fn render_kanban_tab(stdout: &mut Stdout, app: &mut App, cols: u16, rows: u16) -
61816247
let (x_margin, gap) = choose_layout(width, 4);
61826248
let x = x_margin as u16;
61836249
let y_help = rows.saturating_sub(5);
6184-
let today = Utc::now().date_naive();
6250+
let today = Local::now().date_naive();
61856251

61866252
queue!(
61876253
stdout,
@@ -6299,12 +6365,18 @@ fn render_kanban_tab(stdout: &mut Stdout, app: &mut App, cols: u16, rows: u16) -
62996365

63006366
// Due date string.
63016367
let due_str: Option<String> = task.due_date.map(|d| {
6368+
let show_year = d.year() != today.year();
6369+
let date_fmt = if show_year {
6370+
d.format("%b %d %Y").to_string()
6371+
} else {
6372+
d.format("%b %d").to_string()
6373+
};
63026374
if d < today {
6303-
format!("⚠ {}", d.format("%b %d"))
6375+
format!("⚠ {}", date_fmt)
63046376
} else if d == today {
63056377
"due today".to_string()
63066378
} else {
6307-
d.format("%b %d").to_string()
6379+
date_fmt
63086380
}
63096381
});
63106382

0 commit comments

Comments
 (0)