use crate::app::{App, DialogMode, Focus};
use crate::filters::{FilterDialogSection, FilterDialogState};
use crossterm::event::KeyCode;
use kanban_domain::CardFilters;
impl App {
pub fn handle_open_filter_dialog(&mut self) {
if self.focus.active != Focus::Cards || self.selection.active_board_index.is_none() {
return;
}
let filters = CardFilters {
show_unassigned_sprints: self.filter.hide_assigned_cards,
selected_sprint_ids: self.filter.active_sprint_filters.clone(),
date_from: None,
date_to: None,
selected_tags: Default::default(),
};
self.filter.dialog_state = Some(FilterDialogState::new(filters));
self.open_dialog(DialogMode::FilterOptions);
}
pub fn handle_filter_options_popup(&mut self, key_code: KeyCode) {
use crossterm::event::KeyCode;
if let Some(ref mut dialog_state) = self.filter.dialog_state {
match key_code {
KeyCode::Esc => {
self.filter.dialog_state = None;
self.pop_mode();
}
KeyCode::Char('j') | KeyCode::Down => match dialog_state.current_section {
FilterDialogSection::Sprints => {
if let Some(board_idx) = self.selection.active_board_index {
if let Some(board) = self.model.boards().get(board_idx) {
let sprint_count = self
.model
.sprints()
.iter()
.filter(|s| s.board_id == board.id)
.count();
let total_items = 1 + sprint_count;
if dialog_state.item_selection < total_items.saturating_sub(1) {
dialog_state.item_selection += 1;
} else {
dialog_state.next_section();
}
}
}
}
_ => {
dialog_state.next_section();
}
},
KeyCode::Char('k') | KeyCode::Up => match dialog_state.current_section {
FilterDialogSection::Sprints => {
if dialog_state.item_selection > 0 {
dialog_state.item_selection -= 1;
} else {
dialog_state.prev_section();
}
}
_ => {
dialog_state.prev_section();
}
},
KeyCode::Char(' ') => {
if dialog_state.current_section == FilterDialogSection::Sprints {
if dialog_state.item_selection == 0 {
dialog_state.filters.show_unassigned_sprints =
!dialog_state.filters.show_unassigned_sprints;
tracing::info!(
"Toggled unassigned sprints filter: {}",
dialog_state.filters.show_unassigned_sprints
);
self.apply_filters();
} else if let Some(board_idx) = self.selection.active_board_index {
let boards = self.model.boards();
if let Some(board) = boards.get(board_idx) {
let sprints = self.model.sprints();
let board_sprints: Vec<_> =
sprints.iter().filter(|s| s.board_id == board.id).collect();
let sprint_idx = dialog_state.item_selection - 1;
if let Some(sprint) = board_sprints.get(sprint_idx) {
if dialog_state
.filters
.selected_sprint_ids
.contains(&sprint.id)
{
dialog_state.filters.selected_sprint_ids.remove(&sprint.id);
} else {
dialog_state.filters.selected_sprint_ids.insert(sprint.id);
}
tracing::info!(
"Toggled sprint: {}",
sprint.formatted_name(board, "sprint")
);
self.apply_filters();
}
}
}
}
}
KeyCode::Enter => {
self.apply_filters();
self.filter.dialog_state = None;
self.pop_mode();
}
_ => {}
}
}
}
fn apply_filters(&mut self) {
if let Some(dialog_state) = &self.filter.dialog_state {
self.filter.hide_assigned_cards = dialog_state.filters.show_unassigned_sprints;
self.filter.active_sprint_filters = dialog_state.filters.selected_sprint_ids.clone();
tracing::info!(
"Applied filters: unassigned={}, sprints={}",
self.filter.hide_assigned_cards,
self.filter.active_sprint_filters.len()
);
}
}
}