Basic page layout, help, and configuration
This commit is contained in:
parent
2f0cc79631
commit
ead09c4a80
5 changed files with 301 additions and 53 deletions
141
src/app.rs
141
src/app.rs
|
|
@ -1,19 +1,40 @@
|
|||
use std::process::Command;
|
||||
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers};
|
||||
use crate::state::{AppState, TimeItem};
|
||||
use crate::config::Config;
|
||||
|
||||
pub enum Screen {
|
||||
Main,
|
||||
Help,
|
||||
ConfigHelp,
|
||||
}
|
||||
|
||||
pub struct App {
|
||||
pub state: AppState,
|
||||
pub config: Config,
|
||||
pub current_screen: Screen,
|
||||
pub needs_redraw: bool,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new() -> anyhow::Result<Self> {
|
||||
Ok(Self {
|
||||
state: AppState::load()?,
|
||||
config: Config::load()?,
|
||||
current_screen: Screen::Main,
|
||||
needs_redraw: true,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn handle_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
match self.current_screen {
|
||||
Screen::Main => self.handle_main_event(event),
|
||||
Screen::Help => self.handle_help_event(event),
|
||||
Screen::ConfigHelp => self.handle_config_help_event(event),
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_main_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
match event {
|
||||
Event::Key(KeyEvent {
|
||||
code,
|
||||
|
|
@ -27,6 +48,31 @@ impl App {
|
|||
(KeyCode::Char('l'), _) | (KeyCode::Right, _) => self.change_pane(1),
|
||||
(KeyCode::Enter, _) => self.toggle_current_item()?,
|
||||
(KeyCode::Char('e'), KeyModifiers::CONTROL) => self.edit_config()?,
|
||||
(KeyCode::Char('?'), _) => self.current_screen = Screen::Help,
|
||||
(KeyCode::Char('c'), _) => self.edit_app_config()?,
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn handle_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
match event {
|
||||
Event::Key(KeyEvent { code, .. }) => match code {
|
||||
KeyCode::Char('c') => self.current_screen = Screen::ConfigHelp,
|
||||
KeyCode::Esc | KeyCode::Char('q') => self.current_screen = Screen::Main,
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
fn handle_config_help_event(&mut self, event: Event) -> anyhow::Result<bool> {
|
||||
match event {
|
||||
Event::Key(KeyEvent { code, .. }) => match code {
|
||||
KeyCode::Esc | KeyCode::Char('q') => self.current_screen = Screen::Help,
|
||||
_ => {}
|
||||
},
|
||||
_ => {}
|
||||
|
|
@ -79,7 +125,49 @@ impl App {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn edit_config(&self) -> anyhow::Result<()> {
|
||||
fn edit_app_config(&mut self) -> anyhow::Result<()> {
|
||||
use crossterm::{
|
||||
terminal::{disable_raw_mode, enable_raw_mode},
|
||||
execute,
|
||||
terminal::{LeaveAlternateScreen, EnterAlternateScreen},
|
||||
};
|
||||
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()?;
|
||||
|
||||
if status.success() {
|
||||
// Reload entire application state
|
||||
self.config = Config::load()?;
|
||||
// Signal for complete reload
|
||||
self.current_screen = Screen::Main;
|
||||
self.needs_redraw = true;
|
||||
}
|
||||
|
||||
// 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},
|
||||
};
|
||||
use std::io::stdout;
|
||||
|
||||
let editor = std::env::var("EDITOR").unwrap_or_else(|_| "vi".to_string());
|
||||
let config_path = AppState::config_file()?;
|
||||
|
||||
|
|
@ -87,42 +175,27 @@ impl App {
|
|||
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")?;
|
||||
}
|
||||
|
||||
Command::new(editor)
|
||||
.arg(&config_path)
|
||||
.spawn()?
|
||||
.wait()?;
|
||||
// Leave TUI mode
|
||||
disable_raw_mode()?;
|
||||
execute!(stdout(), LeaveAlternateScreen)?;
|
||||
|
||||
// Reload configuration
|
||||
if config_path.exists() {
|
||||
let contents = std::fs::read_to_string(config_path)?;
|
||||
let config: serde_yaml::Value = serde_yaml::from_str(&contents)?;
|
||||
|
||||
if let Some(items) = config["permanent_items"].as_sequence() {
|
||||
// Clear existing permanent items
|
||||
self.state.permanent_items.clear();
|
||||
|
||||
// Add new items from config
|
||||
for item in items {
|
||||
if let (Some(name), Some(tags)) = (
|
||||
item["name"].as_str(),
|
||||
item["tags"].as_sequence()
|
||||
) {
|
||||
let tags = tags
|
||||
.iter()
|
||||
.filter_map(|t| t.as_str())
|
||||
.map(String::from)
|
||||
.collect();
|
||||
|
||||
self.state.permanent_items.push(TimeItem {
|
||||
name: name.to_string(),
|
||||
tags,
|
||||
last_used: None,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
// Run editor
|
||||
let status = Command::new(editor)
|
||||
.arg(&config_path)
|
||||
.status()?;
|
||||
|
||||
if status.success() {
|
||||
// Reload entire application state
|
||||
self.state = AppState::load()?;
|
||||
// Signal for complete reload
|
||||
self.current_screen = Screen::Main;
|
||||
self.needs_redraw = true;
|
||||
}
|
||||
|
||||
// Return to TUI mode
|
||||
execute!(stdout(), EnterAlternateScreen)?;
|
||||
enable_raw_mode()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue