Implement item deletion
This commit is contained in:
parent
b1570a5e11
commit
401ee37b32
2 changed files with 126 additions and 16 deletions
73
src/app.rs
73
src/app.rs
|
|
@ -20,6 +20,7 @@ pub struct App {
|
||||||
pub new_entry_project: String,
|
pub new_entry_project: String,
|
||||||
pub new_entry_cursor: usize,
|
pub new_entry_cursor: usize,
|
||||||
pub new_entry_mode: NewEntryMode, // Task or Project
|
pub new_entry_mode: NewEntryMode, // Task or Project
|
||||||
|
pub status_message: Option<(String, std::time::Instant)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum NewEntryMode {
|
pub enum NewEntryMode {
|
||||||
|
|
@ -38,10 +39,14 @@ impl App {
|
||||||
new_entry_project: String::new(),
|
new_entry_project: String::new(),
|
||||||
new_entry_cursor: 0,
|
new_entry_cursor: 0,
|
||||||
new_entry_mode: NewEntryMode::Task,
|
new_entry_mode: NewEntryMode::Task,
|
||||||
|
status_message: None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
pub fn handle_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||||
|
// Update status message
|
||||||
|
self.update_status_message();
|
||||||
|
|
||||||
match self.current_screen {
|
match self.current_screen {
|
||||||
Screen::Main => self.handle_main_event(event),
|
Screen::Main => self.handle_main_event(event),
|
||||||
Screen::Help => self.handle_help_event(event),
|
Screen::Help => self.handle_help_event(event),
|
||||||
|
|
@ -69,6 +74,7 @@ impl App {
|
||||||
(KeyCode::Char('?'), _) => self.current_screen = Screen::Help,
|
(KeyCode::Char('?'), _) => self.current_screen = Screen::Help,
|
||||||
(KeyCode::Char('c'), _) => self.edit_app_config()?,
|
(KeyCode::Char('c'), _) => self.edit_app_config()?,
|
||||||
(KeyCode::Char('n'), _) => self.start_new_entry(),
|
(KeyCode::Char('n'), _) => self.start_new_entry(),
|
||||||
|
(KeyCode::Char('d'), _) => self.delete_current_item()?,
|
||||||
_ => {}
|
_ => {}
|
||||||
},
|
},
|
||||||
_ => {}
|
_ => {}
|
||||||
|
|
@ -231,6 +237,73 @@ impl App {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn delete_current_item(&mut self) -> anyhow::Result<()> {
|
||||||
|
// Check if this is the active timer
|
||||||
|
let should_stop = {
|
||||||
|
let items = match self.state.current_pane {
|
||||||
|
0 => &self.state.permanent_items,
|
||||||
|
1 => &self.state.recurring_items,
|
||||||
|
2 => &self.state.recent_items,
|
||||||
|
_ => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let index = self.state.selected_indices[self.state.current_pane];
|
||||||
|
|
||||||
|
if !items.is_empty() && index < items.len() {
|
||||||
|
if let Some((ref active, _)) = self.state.active_timer {
|
||||||
|
items[index].name == active.name
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Stop timer if needed
|
||||||
|
if should_stop {
|
||||||
|
self.state.stop_timer()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now delete the item
|
||||||
|
let items = match self.state.current_pane {
|
||||||
|
0 => &mut self.state.permanent_items,
|
||||||
|
1 => &mut self.state.recurring_items,
|
||||||
|
2 => &mut self.state.recent_items,
|
||||||
|
_ => return Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
let index = self.state.selected_indices[self.state.current_pane];
|
||||||
|
|
||||||
|
if !items.is_empty() && index < items.len() {
|
||||||
|
// Remove the item
|
||||||
|
items.remove(index);
|
||||||
|
|
||||||
|
// Adjust index if we're at the end
|
||||||
|
if !items.is_empty() && index == items.len() {
|
||||||
|
self.state.selected_indices[self.state.current_pane] = items.len() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save changes
|
||||||
|
self.state.save()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_status_message<S: Into<String>>(&mut self, message: S) {
|
||||||
|
self.status_message = Some((message.into(), std::time::Instant::now()));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_status_message(&mut self) {
|
||||||
|
// Clear status message after 3 seconds
|
||||||
|
if let Some((_, instant)) = self.status_message {
|
||||||
|
if instant.elapsed().as_secs() >= 3 {
|
||||||
|
self.status_message = None;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn start_new_entry(&mut self) {
|
fn start_new_entry(&mut self) {
|
||||||
self.current_screen = Screen::NewEntry;
|
self.current_screen = Screen::NewEntry;
|
||||||
self.new_entry_buffer.clear();
|
self.new_entry_buffer.clear();
|
||||||
|
|
|
||||||
69
src/ui.rs
69
src/ui.rs
|
|
@ -23,12 +23,19 @@ pub fn render(frame: &mut Frame, app: &App) {
|
||||||
fn render_main(frame: &mut Frame, app: &App) {
|
fn render_main(frame: &mut Frame, app: &App) {
|
||||||
// Calculate layout - accounting for bottom bar if needed
|
// Calculate layout - accounting for bottom bar if needed
|
||||||
let show_bottom_bar = app.config.show_help_hint || app.config.show_command_hints;
|
let show_bottom_bar = app.config.show_help_hint || app.config.show_command_hints;
|
||||||
let constraints = if show_bottom_bar {
|
let has_status = app.status_message.is_some();
|
||||||
|
let bottom_height = if show_bottom_bar {
|
||||||
|
if has_status { 2 } else { 1 }
|
||||||
|
} else {
|
||||||
|
if has_status { 1 } else { 0 }
|
||||||
|
};
|
||||||
|
|
||||||
|
let constraints = if bottom_height > 0 {
|
||||||
vec![
|
vec![
|
||||||
Constraint::Min(3), // At least 3 lines for each section
|
Constraint::Min(3), // At least 3 lines for each section
|
||||||
Constraint::Min(3),
|
Constraint::Min(3),
|
||||||
Constraint::Min(3),
|
Constraint::Min(3),
|
||||||
Constraint::Length(1), // Command bar
|
Constraint::Length(bottom_height), // Command bar + optional status
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
vec![
|
vec![
|
||||||
|
|
@ -43,7 +50,7 @@ fn render_main(frame: &mut Frame, app: &App) {
|
||||||
.constraints(constraints)
|
.constraints(constraints)
|
||||||
.split(frame.size());
|
.split(frame.size());
|
||||||
|
|
||||||
let main_height = if show_bottom_bar {
|
let main_height = if bottom_height > 0 {
|
||||||
chunks[0].height + chunks[1].height + chunks[2].height
|
chunks[0].height + chunks[1].height + chunks[2].height
|
||||||
} else {
|
} else {
|
||||||
frame.size().height
|
frame.size().height
|
||||||
|
|
@ -90,13 +97,8 @@ fn render_main(frame: &mut Frame, app: &App) {
|
||||||
);
|
);
|
||||||
|
|
||||||
// Render bottom bar if needed
|
// Render bottom bar if needed
|
||||||
if show_bottom_bar {
|
if bottom_height > 0 {
|
||||||
let bottom_area = Rect::new(
|
let bottom_area = chunks[3];
|
||||||
0,
|
|
||||||
frame.size().height - 1,
|
|
||||||
frame.size().width,
|
|
||||||
1,
|
|
||||||
);
|
|
||||||
render_bottom_bar(frame, bottom_area, app);
|
render_bottom_bar(frame, bottom_area, app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -173,10 +175,39 @@ fn render_new_entry(frame: &mut Frame, app: &App) {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_bottom_bar(frame: &mut Frame, area: Rect, app: &App) {
|
fn render_bottom_bar(frame: &mut Frame, area: Rect, app: &App) {
|
||||||
if app.config.show_command_hints {
|
// Split the area into status and command sections if needed
|
||||||
|
let chunks = if app.status_message.is_some() {
|
||||||
|
Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints([
|
||||||
|
Constraint::Length(1), // Status message
|
||||||
|
Constraint::Length(1), // Command bar
|
||||||
|
])
|
||||||
|
.split(area)
|
||||||
|
} else {
|
||||||
|
Layout::default()
|
||||||
|
.direction(Direction::Vertical)
|
||||||
|
.constraints([Constraint::Length(1)])
|
||||||
|
.split(area)
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut command_line_idx = 0;
|
||||||
|
|
||||||
|
// Render status message if present
|
||||||
|
if let Some((ref message, _)) = app.status_message {
|
||||||
|
let text = Paragraph::new(message.as_str())
|
||||||
|
.style(Style::default().fg(Color::Yellow))
|
||||||
|
.alignment(Alignment::Center);
|
||||||
|
frame.render_widget(text, chunks[0]);
|
||||||
|
command_line_idx = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render command hints
|
||||||
|
if app.config.show_command_hints && chunks.len() > command_line_idx {
|
||||||
let commands = vec![
|
let commands = vec![
|
||||||
("c", "config"),
|
("c", "config"),
|
||||||
("n", "new"),
|
("n", "new"),
|
||||||
|
("d", "delete"),
|
||||||
("q", "quit"),
|
("q", "quit"),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -187,9 +218,14 @@ fn render_bottom_bar(frame: &mut Frame, area: Rect, app: &App) {
|
||||||
|
|
||||||
let command_area = if app.config.show_help_hint {
|
let command_area = if app.config.show_help_hint {
|
||||||
// Leave space for help hint
|
// Leave space for help hint
|
||||||
Rect::new(area.x, area.y, area.width.saturating_sub(12), area.height)
|
Rect::new(
|
||||||
|
chunks[command_line_idx].x,
|
||||||
|
chunks[command_line_idx].y,
|
||||||
|
chunks[command_line_idx].width.saturating_sub(12),
|
||||||
|
1
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
area
|
chunks[command_line_idx]
|
||||||
};
|
};
|
||||||
|
|
||||||
let command_bar = Paragraph::new(command_text)
|
let command_bar = Paragraph::new(command_text)
|
||||||
|
|
@ -199,14 +235,14 @@ fn render_bottom_bar(frame: &mut Frame, area: Rect, app: &App) {
|
||||||
frame.render_widget(command_bar, command_area);
|
frame.render_widget(command_bar, command_area);
|
||||||
}
|
}
|
||||||
|
|
||||||
if app.config.show_help_hint {
|
if app.config.show_help_hint && chunks.len() > command_line_idx {
|
||||||
let help_hint = Paragraph::new("(?) for help")
|
let help_hint = Paragraph::new("(?) for help")
|
||||||
.alignment(Alignment::Right)
|
.alignment(Alignment::Right)
|
||||||
.style(Style::default().fg(Color::DarkGray));
|
.style(Style::default().fg(Color::DarkGray));
|
||||||
|
|
||||||
let help_area = Rect::new(
|
let help_area = Rect::new(
|
||||||
area.width.saturating_sub(12),
|
chunks[command_line_idx].x + chunks[command_line_idx].width.saturating_sub(12),
|
||||||
area.y,
|
chunks[command_line_idx].y,
|
||||||
12,
|
12,
|
||||||
1,
|
1,
|
||||||
);
|
);
|
||||||
|
|
@ -267,6 +303,7 @@ fn render_help(frame: &mut Frame, _app: &App) {
|
||||||
"j/k, arrows - Navigate",
|
"j/k, arrows - Navigate",
|
||||||
"h/l, arrows - Switch panes",
|
"h/l, arrows - Switch panes",
|
||||||
"Enter - Start/stop timer",
|
"Enter - Start/stop timer",
|
||||||
|
"d - Delete task",
|
||||||
"Ctrl+e - Edit tasks config",
|
"Ctrl+e - Edit tasks config",
|
||||||
"c - Edit app config",
|
"c - Edit app config",
|
||||||
"n - New task",
|
"n - New task",
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue