use crate::components::Component;
use crate::services::GitService;
use crate::app::{AppState, Action, reducer};
use crate::errors::ComponentError;
use crate::input::InputEvent;
use crate::ui::style;
use ratatui::Frame;
use ratatui::layout::Rect;
use ratatui::widgets::{List, ListItem};
use ratatui::style::Style;
use crossterm::event::{KeyCode, KeyEventKind};
use std::sync::Arc;
pub struct StashPane {
git_service: Arc<GitService>,
}
impl StashPane {
pub fn new(git_service: Arc<GitService>) -> Self {
Self { git_service }
}
}
impl Component for StashPane {
fn handle_event(
&mut self,
event: InputEvent,
state: &AppState,
) -> Result<Option<Action>, ComponentError> {
match event {
InputEvent::Key(key) if key.kind == KeyEventKind::Press => {
match key.code {
KeyCode::Esc => {
Ok(Some(Action::FocusPrev)) }
KeyCode::Char('k') | KeyCode::Up => {
Ok(Some(Action::StashUp))
}
KeyCode::Char('j') | KeyCode::Down => {
Ok(Some(Action::StashDown))
}
KeyCode::Enter => {
if let Some(stash) = state.stashes.get(state.stash_selected) {
Ok(Some(Action::ApplyStash(stash.name.clone())))
} else {
Ok(None)
}
}
KeyCode::Char('P') => {
if let Some(stash) = state.stashes.get(state.stash_selected) {
Ok(Some(Action::PopStash(stash.name.clone())))
} else {
Ok(None)
}
}
KeyCode::Char('D') => {
if let Some(stash) = state.stashes.get(state.stash_selected) {
Ok(Some(Action::DeleteStash(stash.name.clone())))
} else {
Ok(None)
}
}
_ => Ok(None),
}
}
_ => Ok(None),
}
}
fn update(
&mut self,
action: Action,
state: &mut AppState,
) -> Result<(), ComponentError> {
match action {
Action::RefreshStashes => {
let path = state.repo_path.clone();
match self.git_service.stash_list(&path) {
Ok(stashes) => {
*state = reducer(state.clone(), Action::SetStashes(stashes));
}
Err(e) => {
tracing::warn!(error = %e, "stash list error");
}
}
}
_ => {}
}
Ok(())
}
fn render(&mut self, frame: &mut Frame, area: Rect, state: &AppState) {
let theme = &state.theme;
let selection_style = style::selection(theme);
let items: Vec<ListItem> = if state.stashes.is_empty() {
vec![ListItem::new("No stashes").style(style::text(theme, crate::ui::style::Emphasis::Muted))]
} else {
state.stashes
.iter()
.enumerate()
.map(|(i, stash)| {
let style = if i == state.stash_selected {
selection_style
} else {
Style::default().fg(theme.untracked_color())
};
ListItem::new(format!("{} - {}", stash.name, stash.message))
.style(style)
})
.collect()
};
let list = List::new(items)
.style(style::body_style(theme))
.block(style::pane_block(theme, "Stashes", false));
frame.render_widget(list, area);
}
fn name(&self) -> &'static str {
"StashPane"
}
}