UI Improvements
This commit is contained in:
+24
-1
@@ -465,6 +465,7 @@ impl App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// True if the active device supports transmit (HackRF only; RTL-SDR is receive-only).
|
/// True if the active device supports transmit (HackRF only; RTL-SDR is receive-only).
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn can_transmit(&self) -> bool {
|
pub fn can_transmit(&self) -> bool {
|
||||||
self.radio.as_ref().map_or(false, |r| r.supports_tx())
|
self.radio.as_ref().map_or(false, |r| r.supports_tx())
|
||||||
}
|
}
|
||||||
@@ -983,9 +984,31 @@ impl App {
|
|||||||
|
|
||||||
// -- Signal Action Menu helpers --
|
// -- Signal Action Menu helpers --
|
||||||
|
|
||||||
|
/// Signal actions shown in the menu: all if HackRF (TX), else only export and delete.
|
||||||
|
pub fn available_signal_actions(&self) -> Vec<SignalAction> {
|
||||||
|
if self.radio.as_ref().map_or(false, |r| r.supports_tx()) {
|
||||||
|
SignalAction::ALL.to_vec()
|
||||||
|
} else {
|
||||||
|
SignalAction::ALL
|
||||||
|
.iter()
|
||||||
|
.filter(|a| {
|
||||||
|
matches!(
|
||||||
|
a,
|
||||||
|
SignalAction::ExportFob | SignalAction::ExportFlipper | SignalAction::Delete
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.copied()
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute the currently selected signal action
|
/// Execute the currently selected signal action
|
||||||
pub fn execute_signal_action(&mut self) -> Result<()> {
|
pub fn execute_signal_action(&mut self) -> Result<()> {
|
||||||
let action = SignalAction::ALL[self.signal_menu_index];
|
let actions = self.available_signal_actions();
|
||||||
|
let idx = self
|
||||||
|
.signal_menu_index
|
||||||
|
.min(actions.len().saturating_sub(1));
|
||||||
|
let action = actions[idx];
|
||||||
let capture_id = match self.selected_capture {
|
let capture_id = match self.selected_capture {
|
||||||
Some(idx) if idx < self.captures.len() => self.captures[idx].id,
|
Some(idx) if idx < self.captures.len() => self.captures[idx].id,
|
||||||
_ => {
|
_ => {
|
||||||
|
|||||||
+3
-2
@@ -23,7 +23,7 @@ use std::io::{self, Write};
|
|||||||
use std::panic;
|
use std::panic;
|
||||||
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
|
||||||
|
|
||||||
use app::{App, InputMode, SignalAction, SettingsField, ExportFormat};
|
use app::{App, InputMode, SettingsField, ExportFormat};
|
||||||
use ui::draw_ui;
|
use ui::draw_ui;
|
||||||
|
|
||||||
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||||
@@ -188,7 +188,8 @@ fn run_app<B: ratatui::backend::Backend>(terminal: &mut Terminal<B>, app: &mut A
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
KeyCode::Down | KeyCode::Char('j') => {
|
KeyCode::Down | KeyCode::Char('j') => {
|
||||||
if app.signal_menu_index < SignalAction::ALL.len() - 1 {
|
let len = app.available_signal_actions().len();
|
||||||
|
if len > 0 && app.signal_menu_index < len - 1 {
|
||||||
app.signal_menu_index += 1;
|
app.signal_menu_index += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-15
@@ -29,10 +29,12 @@ pub fn render_signal_menu(frame: &mut Frame, app: &App) {
|
|||||||
("No capture".to_string(), String::new())
|
("No capture".to_string(), String::new())
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let actions = app.available_signal_actions();
|
||||||
|
|
||||||
// Menu dimensions - wider to show more info
|
// Menu dimensions - wider to show more info
|
||||||
let menu_width = 38u16;
|
let menu_width = 38u16;
|
||||||
let extra_lines = if freq_info.is_empty() { 0u16 } else { 2u16 };
|
let extra_lines = if freq_info.is_empty() { 0u16 } else { 2u16 };
|
||||||
let menu_height = (SignalAction::ALL.len() as u16) + 4 + extra_lines;
|
let menu_height = (actions.len() as u16) + 4 + extra_lines;
|
||||||
|
|
||||||
// Center the menu
|
// Center the menu
|
||||||
let x = area.width.saturating_sub(menu_width) / 2;
|
let x = area.width.saturating_sub(menu_width) / 2;
|
||||||
@@ -54,8 +56,8 @@ pub fn render_signal_menu(frame: &mut Frame, app: &App) {
|
|||||||
items.push(ListItem::new(Line::from(Span::raw(""))));
|
items.push(ListItem::new(Line::from(Span::raw(""))));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add action items
|
// Add action items (only available actions are shown)
|
||||||
for (i, action) in SignalAction::ALL.iter().enumerate() {
|
for (i, action) in actions.iter().enumerate() {
|
||||||
let style = if i == app.signal_menu_index {
|
let style = if i == app.signal_menu_index {
|
||||||
Style::default()
|
Style::default()
|
||||||
.fg(Color::Black)
|
.fg(Color::Black)
|
||||||
@@ -77,19 +79,8 @@ pub fn render_signal_menu(frame: &mut Frame, app: &App) {
|
|||||||
" "
|
" "
|
||||||
};
|
};
|
||||||
|
|
||||||
let is_tx_action = matches!(
|
|
||||||
action,
|
|
||||||
SignalAction::Replay | SignalAction::Lock | SignalAction::Unlock
|
|
||||||
| SignalAction::Trunk | SignalAction::Panic
|
|
||||||
);
|
|
||||||
let suffix = if is_tx_action && !app.can_transmit() {
|
|
||||||
" (no TX)"
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
};
|
|
||||||
|
|
||||||
items.push(ListItem::new(Line::from(Span::styled(
|
items.push(ListItem::new(Line::from(Span::styled(
|
||||||
format!("{}{}{}", prefix, action.label(), suffix),
|
format!("{}{}", prefix, action.label()),
|
||||||
style,
|
style,
|
||||||
))));
|
))));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user