Fix projects, remove output in interface, log output to file
This commit is contained in:
parent
401ee37b32
commit
ae045167bf
5 changed files with 274 additions and 162 deletions
119
src/app.rs
119
src/app.rs
|
|
@ -1,8 +1,8 @@
|
|||
use std::process::Command;
|
||||
use crate::config::Config;
|
||||
use crate::state::{AppState, TimeItem};
|
||||
use chrono::Utc;
|
||||
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
|
||||
use crate::state::{AppState, TimeItem};
|
||||
use crate::config::Config;
|
||||
use std::process::Command;
|
||||
|
||||
pub enum Screen {
|
||||
Main,
|
||||
|
|
@ -19,7 +19,7 @@ pub struct App {
|
|||
pub new_entry_buffer: String,
|
||||
pub new_entry_project: String,
|
||||
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)>,
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +46,7 @@ impl App {
|
|||
pub fn handle_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
// Update status message
|
||||
self.update_status_message();
|
||||
|
||||
|
||||
match self.current_screen {
|
||||
Screen::Main => self.handle_main_event(event),
|
||||
Screen::Help => self.handle_help_event(event),
|
||||
|
|
@ -58,9 +58,7 @@ impl App {
|
|||
fn handle_main_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
match event {
|
||||
Event::Key(KeyEvent {
|
||||
code,
|
||||
modifiers,
|
||||
..
|
||||
code, modifiers, ..
|
||||
}) => match (code, modifiers) {
|
||||
(KeyCode::Char('q'), _) => return Ok(true),
|
||||
(KeyCode::Char('j'), _) | (KeyCode::Down, _) => self.move_selection(1),
|
||||
|
|
@ -85,9 +83,7 @@ impl App {
|
|||
fn handle_new_entry_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
match event {
|
||||
Event::Key(KeyEvent {
|
||||
code,
|
||||
modifiers,
|
||||
..
|
||||
code, modifiers, ..
|
||||
}) => {
|
||||
match (code, modifiers) {
|
||||
(KeyCode::Esc, _) => {
|
||||
|
|
@ -95,16 +91,20 @@ impl App {
|
|||
self.new_entry_buffer.clear();
|
||||
self.new_entry_project.clear();
|
||||
self.new_entry_mode = NewEntryMode::Task;
|
||||
self.new_entry_cursor = 0;
|
||||
}
|
||||
(KeyCode::Enter, _) => {
|
||||
match self.new_entry_mode {
|
||||
NewEntryMode::Task => {
|
||||
if !self.new_entry_buffer.is_empty() {
|
||||
self.new_entry_mode = NewEntryMode::Project;
|
||||
self.new_entry_cursor = self.new_entry_project.len();
|
||||
}
|
||||
}
|
||||
NewEntryMode::Project => {
|
||||
if self.new_entry_project.is_empty() || self.config.is_valid_project(&self.new_entry_project) {
|
||||
if self.new_entry_project.is_empty()
|
||||
|| self.config.is_valid_project(&self.new_entry_project)
|
||||
{
|
||||
// Create new time item
|
||||
let item = TimeItem {
|
||||
name: self.new_entry_buffer.clone(),
|
||||
|
|
@ -117,13 +117,13 @@ impl App {
|
|||
};
|
||||
// Add to current pane (or recurring if in recent)
|
||||
match self.state.current_pane {
|
||||
0 => self.state.permanent_items.push(item), // Permanent Items
|
||||
1 => self.state.recurring_items.push(item), // Recurring Items
|
||||
2 => self.state.recent_items.push(item), // Ad-Hoc Items
|
||||
0 => self.state.permanent_items.push(item), // Permanent Items
|
||||
1 => self.state.recurring_items.push(item), // Recurring Items
|
||||
2 => self.state.recent_items.push(item), // Ad-Hoc Items
|
||||
_ => unreachable!(),
|
||||
}
|
||||
self.state.save()?;
|
||||
|
||||
|
||||
// Clear and return to main screen
|
||||
self.current_screen = Screen::Main;
|
||||
self.new_entry_buffer.clear();
|
||||
|
|
@ -133,34 +133,35 @@ impl App {
|
|||
}
|
||||
}
|
||||
}
|
||||
(KeyCode::Backspace, _) => {
|
||||
match self.new_entry_mode {
|
||||
NewEntryMode::Task => {
|
||||
if self.new_entry_cursor > 0 {
|
||||
self.new_entry_buffer.remove(self.new_entry_cursor - 1);
|
||||
self.new_entry_cursor -= 1;
|
||||
}
|
||||
(KeyCode::Backspace, _) => match self.new_entry_mode {
|
||||
NewEntryMode::Task => {
|
||||
if self.new_entry_cursor > 0 {
|
||||
self.new_entry_buffer.remove(self.new_entry_cursor - 1);
|
||||
self.new_entry_cursor -= 1;
|
||||
}
|
||||
NewEntryMode::Project => {
|
||||
if self.new_entry_cursor > 0 {
|
||||
self.new_entry_project.remove(self.new_entry_cursor - 1);
|
||||
}
|
||||
NewEntryMode::Project => {
|
||||
if self.new_entry_cursor > 0 {
|
||||
let idx = self.new_entry_cursor - 1;
|
||||
if idx < self.new_entry_project.len() {
|
||||
self.new_entry_project.remove(idx);
|
||||
self.new_entry_cursor -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
(KeyCode::Char(c), m) if m.is_empty() => {
|
||||
match self.new_entry_mode {
|
||||
NewEntryMode::Task => {
|
||||
self.new_entry_buffer.insert(self.new_entry_cursor, c);
|
||||
self.new_entry_cursor += 1;
|
||||
}
|
||||
NewEntryMode::Project => {
|
||||
},
|
||||
(KeyCode::Char(c), m) if m.is_empty() => match self.new_entry_mode {
|
||||
NewEntryMode::Task => {
|
||||
self.new_entry_buffer.insert(self.new_entry_cursor, c);
|
||||
self.new_entry_cursor += 1;
|
||||
}
|
||||
NewEntryMode::Project => {
|
||||
if self.new_entry_cursor <= self.new_entry_project.len() {
|
||||
self.new_entry_project.insert(self.new_entry_cursor, c);
|
||||
self.new_entry_cursor += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -227,7 +228,13 @@ impl App {
|
|||
|
||||
fn toggle_current_item(&mut self) -> anyhow::Result<()> {
|
||||
if let Some(item) = self.get_current_item() {
|
||||
if self.state.active_timer.as_ref().map(|(active, _)| active.name == item.name).unwrap_or(false) {
|
||||
if self
|
||||
.state
|
||||
.active_timer
|
||||
.as_ref()
|
||||
.map(|(active, _)| active.name == item.name)
|
||||
.unwrap_or(false)
|
||||
{
|
||||
self.state.stop_timer()?;
|
||||
} else {
|
||||
self.state.start_timer(item)?;
|
||||
|
|
@ -248,7 +255,7 @@ impl App {
|
|||
};
|
||||
|
||||
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
|
||||
|
|
@ -274,20 +281,20 @@ impl App {
|
|||
};
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
|
|
@ -314,23 +321,21 @@ impl App {
|
|||
|
||||
fn edit_app_config(&mut self) -> anyhow::Result<()> {
|
||||
use crossterm::{
|
||||
terminal::{disable_raw_mode, enable_raw_mode},
|
||||
execute,
|
||||
terminal::{LeaveAlternateScreen, EnterAlternateScreen},
|
||||
terminal::{disable_raw_mode, enable_raw_mode},
|
||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::io::stdout;
|
||||
|
||||
|
||||
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
|
||||
let config_path = Config::config_path()?;
|
||||
|
||||
|
||||
// Leave TUI mode
|
||||
disable_raw_mode()?;
|
||||
execute!(stdout(), LeaveAlternateScreen)?;
|
||||
|
||||
// Run editor
|
||||
let status = Command::new(editor)
|
||||
.arg(&config_path)
|
||||
.status()?;
|
||||
let status = Command::new(editor).arg(&config_path).status()?;
|
||||
|
||||
if status.success() {
|
||||
// Reload entire application state
|
||||
|
|
@ -343,21 +348,21 @@ impl App {
|
|||
// Return to TUI mode
|
||||
execute!(stdout(), EnterAlternateScreen)?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn edit_config(&mut self) -> anyhow::Result<()> {
|
||||
use crossterm::{
|
||||
terminal::{disable_raw_mode, enable_raw_mode},
|
||||
execute,
|
||||
terminal::{LeaveAlternateScreen, EnterAlternateScreen},
|
||||
terminal::{disable_raw_mode, enable_raw_mode},
|
||||
terminal::{EnterAlternateScreen, LeaveAlternateScreen},
|
||||
};
|
||||
use std::io::stdout;
|
||||
|
||||
|
||||
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
|
||||
let config_path = AppState::config_file()?;
|
||||
|
||||
|
||||
if !config_path.exists() {
|
||||
std::fs::write(&config_path, "# WAT Configuration\n# Add your permanent items here\n\npermanent_items:\n - name: Daily Standup\n tags: [daily, meeting]\n")?;
|
||||
}
|
||||
|
|
@ -367,9 +372,7 @@ impl App {
|
|||
execute!(stdout(), LeaveAlternateScreen)?;
|
||||
|
||||
// Run editor
|
||||
let status = Command::new(editor)
|
||||
.arg(&config_path)
|
||||
.status()?;
|
||||
let status = Command::new(editor).arg(&config_path).status()?;
|
||||
|
||||
if status.success() {
|
||||
// Reload entire application state
|
||||
|
|
@ -382,7 +385,7 @@ impl App {
|
|||
// Return to TUI mode
|
||||
execute!(stdout(), EnterAlternateScreen)?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue