Skip to content

Commit 2b07e01

Browse files
committed
Fix modal interactions and improve UX
- Fix directory item counting in file info modals - Add responsive modal sizing based on content - Implement highlighted close button with [ Close ] text - Block all other interactions when modal is open - Add Enter key as modal close option - Fix KeyCode::Esc compilation error
1 parent 162e2eb commit 2b07e01

File tree

2 files changed

+74
-35
lines changed

2 files changed

+74
-35
lines changed

src/app.rs

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,17 @@ impl App {
373373
}
374374

375375
pub fn handle_key_event(&mut self, key: KeyCode) {
376+
// Handle modal keys first - they take priority
377+
if self.show_modal {
378+
match key {
379+
KeyCode::Char('i') | KeyCode::Char('q') | KeyCode::Esc | KeyCode::Enter => {
380+
self.hide_modal();
381+
}
382+
_ => {} // Ignore all other keys when modal is open
383+
}
384+
return;
385+
}
386+
376387
if self.show_help {
377388
match key {
378389
KeyCode::Esc | KeyCode::Char('?') | KeyCode::Char('h') => {
@@ -385,13 +396,7 @@ impl App {
385396

386397
match key {
387398
KeyCode::Char('q') | KeyCode::Esc => {
388-
if self.show_modal {
389-
self.hide_modal();
390-
} else if self.show_help {
391-
self.show_help = false;
392-
} else {
393-
self.should_quit = true;
394-
}
399+
self.should_quit = true;
395400
}
396401
KeyCode::Left | KeyCode::Char('h') => {
397402
self.select_previous_panel();
@@ -541,17 +546,12 @@ impl App {
541546
self.show_help = true;
542547
}
543548
KeyCode::Char('i') => {
544-
if self.show_modal {
545-
// Close modal if already open
546-
self.hide_modal();
547-
} else {
548-
// Show info modal based on current panel
549-
match self.selected_panel {
550-
Panel::ProcessManager => self.show_process_modal(),
551-
Panel::NetworkGraph => self.show_network_modal(),
552-
Panel::SystemMonitor | Panel::SystemStatus => self.show_system_modal(),
553-
Panel::FileExplorer => self.show_file_modal(),
554-
}
549+
// Show info modal based on current panel
550+
match self.selected_panel {
551+
Panel::ProcessManager => self.show_process_modal(),
552+
Panel::NetworkGraph => self.show_network_modal(),
553+
Panel::SystemMonitor | Panel::SystemStatus => self.show_system_modal(),
554+
Panel::FileExplorer => self.show_file_modal(),
555555
}
556556
}
557557
KeyCode::Char('b') => {
@@ -736,14 +736,20 @@ impl App {
736736
.to_string();
737737

738738
let content = if is_dir {
739+
// Count directory items
740+
let item_count = match std::fs::read_dir(selected_path) {
741+
Ok(entries) => entries.count(),
742+
Err(_) => 0,
743+
};
744+
739745
format!(
740746
"Name: {}\n\
741747
Type: Directory\n\
742748
Size: {} items\n\
743749
Permissions: {}\n\
744750
Path: {}",
745751
clean_name,
746-
"N/A", // Directory item count would require reading the directory
752+
item_count,
747753
permissions,
748754
selected_path.display()
749755
)

src/ui/modal.rs

Lines changed: 49 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,20 +12,7 @@ pub fn render_modal(app: &App, frame: &mut Frame, area: Rect) {
1212
return;
1313
}
1414

15-
// Create modal area (centered)
16-
let modal_width = (area.width * 3) / 4;
17-
let modal_height = (area.height * 3) / 4;
18-
let modal_x = (area.width - modal_width) / 2;
19-
let modal_y = (area.height - modal_height) / 2;
20-
21-
let modal_area = Rect::new(
22-
area.x + modal_x,
23-
area.y + modal_y,
24-
modal_width,
25-
modal_height,
26-
);
27-
28-
// Create modal content based on type
15+
// Calculate content to determine optimal modal size
2916
let (title, content) = match &app.modal_data {
3017
ModalData::ProcessDetails { name, pid, cpu_usage, memory_usage, status, cmd } => {
3118
let title = format!("Process Details: {}", name);
@@ -111,6 +98,32 @@ pub fn render_modal(app: &App, frame: &mut Frame, area: Rect) {
11198
}
11299
};
113100

101+
// Calculate optimal modal size based on content
102+
let content_lines = content.lines().count() + 3; // +3 for title, spacing, and close button
103+
let max_line_width = content.lines().map(|line| line.len()).max().unwrap_or(20);
104+
105+
let modal_width = std::cmp::min(
106+
std::cmp::max(max_line_width as u16 + 4, 40), // Minimum 40, content width + padding
107+
area.width.saturating_sub(8) // Leave some margin from screen edges
108+
);
109+
let modal_height = std::cmp::min(
110+
std::cmp::max(content_lines as u16 + 2, 8), // Minimum 8, content height + padding
111+
area.height.saturating_sub(6) // Leave some margin from screen edges
112+
);
113+
114+
// Center the modal
115+
let modal_x = (area.width - modal_width) / 2;
116+
let modal_y = (area.height - modal_height) / 2;
117+
118+
let modal_area = Rect::new(
119+
area.x + modal_x,
120+
area.y + modal_y,
121+
modal_width,
122+
modal_height,
123+
);
124+
125+
// Content already calculated above, now render the modal
126+
114127
// Clear the modal area first to ensure no background interference
115128
frame.render_widget(Clear, modal_area);
116129

@@ -119,12 +132,12 @@ pub fn render_modal(app: &App, frame: &mut Frame, area: Rect) {
119132
.style(Style::default().bg(Color::Black));
120133
frame.render_widget(solid_background, modal_area);
121134

122-
// Create content area inside the modal (full height minus borders)
135+
// Create content area inside the modal (leave space for close button)
123136
let content_area = Rect::new(
124137
modal_area.x + 1,
125138
modal_area.y + 1,
126139
modal_area.width - 2,
127-
modal_area.height - 2, // Full height minus borders
140+
modal_area.height - 4, // Leave space for close button
128141
);
129142

130143
// Render modal content with solid black background
@@ -136,6 +149,26 @@ pub fn render_modal(app: &App, frame: &mut Frame, area: Rect) {
136149

137150
frame.render_widget(modal_content, content_area);
138151

152+
// Render close button at the bottom
153+
let button_area = Rect::new(
154+
modal_area.x + 1,
155+
modal_area.y + modal_area.height - 3,
156+
modal_area.width - 2,
157+
1,
158+
);
159+
160+
let close_button = Paragraph::new("[ Close ]")
161+
.style(Style::default()
162+
.fg(Color::Black)
163+
.bg(Color::Yellow)) // Highlighted button
164+
.alignment(Alignment::Center)
165+
.block(Block::default()
166+
.style(Style::default()
167+
.fg(Color::Black)
168+
.bg(Color::Yellow)));
169+
170+
frame.render_widget(close_button, button_area);
171+
139172
// Render the modal border on top with title
140173
let modal_block = Block::default()
141174
.title(title)

0 commit comments

Comments
 (0)