Skip to content

Commit

Permalink
Add notification overlay and other improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ztroop committed Mar 19, 2024
1 parent c488a9f commit 81f458f
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 24 deletions.
20 changes: 16 additions & 4 deletions src/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use uuid::Uuid;
/// A struct to hold the information of a Bluetooth device.
#[derive(Clone, Default)]
pub struct DeviceInfo {
pub id: String,
pub uuid: String,
pub name: String,
pub tx_power: String,
pub address: String,
Expand All @@ -19,8 +19,9 @@ pub struct DeviceInfo {

impl DeviceInfo {
/// Creates a new `DeviceInfo` with the provided information.
#[allow(clippy::too_many_arguments)]
pub fn new(
id: String,
uuid: String,
name: Option<String>,
tx_power: Option<i16>,
address: String,
Expand All @@ -29,8 +30,8 @@ impl DeviceInfo {
services: Vec<Uuid>,
service_data: HashMap<Uuid, Vec<u8>>,
) -> Self {
DeviceInfo {
id,
Self {
uuid,
name: name.unwrap_or_else(|| "Unknown".to_string()),
tx_power: tx_power.map_or_else(|| "n/a".to_string(), |tx| tx.to_string()),
address,
Expand All @@ -41,14 +42,25 @@ impl DeviceInfo {
service_data,
}
}

pub fn get_id(&self) -> String {
// Returns the `uuid` or `address` of the device if MacOS or Linux.
if cfg!(target_os = "macos") {
self.uuid.clone()
} else {
self.address.clone()
}
}
}

/// A struct to hold the information of a GATT Characteristic.
pub struct Characteristic {
pub uuid: Uuid,
pub properties: CharPropFlags,
pub descriptors: Vec<Uuid>,
}

/// A struct to hold the information of a GATT Descriptor.
pub struct ManufacturerData {
pub company_code: String,
pub data: String,
Expand Down
67 changes: 54 additions & 13 deletions src/viewer.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use crossterm::event::{self, Event, KeyCode};
use ratatui::backend::Backend;
use ratatui::widgets::TableState;
use ratatui::layout::Alignment;
use ratatui::text::Span;
use ratatui::widgets::{Block, Borders, Clear, Paragraph, TableState};
use ratatui::{
layout::{Constraint, Direction, Layout},
Terminal,
Expand All @@ -11,10 +13,13 @@ use std::sync::Arc;
use std::time::Duration;
use tokio::sync::mpsc;

use crate::structs::DeviceInfo;
use crate::scan::get_characteristics;
use crate::structs::{Characteristic, DeviceInfo};
use crate::utils::centered_rect;
use crate::widgets::detail_table::detail_table;
use crate::widgets::device_table::device_table;
use crate::widgets::info_table::info_table;
use crate::widgets::inspect_overlay::inspect_overlay;

/// Displays the detected Bluetooth devices in a table and handles the user input.
/// The user can navigate the table, pause the scanning, and quit the application.
Expand All @@ -27,8 +32,11 @@ pub async fn viewer<B: Backend>(
let mut table_state = TableState::default();
table_state.select(Some(0));
let mut devices = Vec::<DeviceInfo>::new();
// let mut inspect_view = false;
// let mut selected_characteristics: Vec<Characteristic> = Vec::new();
let mut inspect_view = false;
let mut selected_characteristics: Vec<Characteristic> = Vec::new();

let mut error_view = false;
let mut error_message = String::new();

loop {
// Draw UI
Expand Down Expand Up @@ -56,31 +64,64 @@ pub async fn viewer<B: Backend>(
f.render_stateful_widget(device_table, chunks[0], &mut table_state);

// Draw the detail table
let detail_table = detail_table(&selected_device);
let detail_table = detail_table(selected_device);
f.render_widget(detail_table, chunks[1]);

// Draw the info table
let info_table = info_table(pause_signal.load(Ordering::SeqCst));
f.render_widget(info_table, chunks[2]);

// if inspect_view {
// let inspect_overlay = inspect_overlay(&selected_characteristics);
// let area = centered_rect(60, 60, f.size());
// f.render_widget(Clear, area);
// f.render_widget(inspect_overlay, area);
// }
// Draw the inspect overlay
if inspect_view {
let inspect_overlay = inspect_overlay(&selected_characteristics);
let area = centered_rect(60, 60, f.size());
f.render_widget(Clear, area);
f.render_widget(inspect_overlay, area);
}

// Draw the error overlay
if error_view {
let error_message_clone = error_message.clone();
let area = centered_rect(60, 10, f.size());
let error_block = Paragraph::new(Span::from(error_message_clone))
.alignment(Alignment::Center) // This centers the text horizontally
.block(Block::default().borders(Borders::ALL).title("Notification"));
f.render_widget(Clear, area);
f.render_widget(error_block, area);
}
})?;

// Event handling
if event::poll(Duration::from_millis(100))? {
if let Event::Key(key) = event::read()? {
match key.code {
KeyCode::Char('q') => break,
KeyCode::Char('q') => {
if error_view {
error_view = false;
} else {
break;
}
}
KeyCode::Char('s') => {
let current_state = pause_signal.load(Ordering::SeqCst);
pause_signal.store(!current_state, Ordering::SeqCst);
}
KeyCode::Enter => {}
KeyCode::Enter => {
let device_binding = &DeviceInfo::default();
let selected_device = devices
.get(table_state.selected().unwrap_or(0))
.unwrap_or(device_binding);
match get_characteristics(&selected_device.get_id()).await {
Ok(characteristics) => {
selected_characteristics = characteristics;
inspect_view = !inspect_view;
}
Err(e) => {
error_message = format!("Error getting characteristics: {}", e);
error_view = true;
}
}
}
KeyCode::Down => {
let next = match table_state.selected() {
Some(selected) => {
Expand Down
7 changes: 1 addition & 6 deletions src/widgets/device_table.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,8 @@ pub fn device_table(selected: Option<usize>, devices: &[DeviceInfo]) -> Table {
} else {
Style::default()
};
let device_address = if device.address == "00:00:00:00:00:00" {
device.id.clone()
} else {
device.address.clone()
};
Row::new(vec![
device_address,
device.get_id(),
device.name.clone(),
device.tx_power.clone(),
device.rssi.clone(),
Expand Down
2 changes: 1 addition & 1 deletion src/widgets/inspect_overlay.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use ratatui::{
use crate::structs::Characteristic;

/// Provides an overlay with the selected device's service data.
pub fn inspect_overlay(characteristics: &Vec<Characteristic>) -> Table<'static> {
pub fn inspect_overlay(characteristics: &[Characteristic]) -> Table<'static> {
// Iterate through the selected device's characteristics to create rows
let rows: Vec<Row> = characteristics
.iter()
Expand Down

0 comments on commit 81f458f

Please sign in to comment.