Added UI base code

This commit is contained in:
benjamyn committed 2024-03-29 19:29:04 +11:00
1 parent 6b54955fd2
commit d932bb234b
5 files changed
+507 -29

No files matched your search

+29
View File
@@ -0,0 +1,29 @@
pub enum AppRenderDir {
Vertical,
Horizontal,
}
pub enum CurrentState {
Lookup,
Menu,
}
pub struct App {
pub domain_input: String,
pub whois_info: Vec<String>,
pub dns_info: Vec<String>,
pub render_direction: AppRenderDir,
pub current_state: CurrentState,
}
impl App {
pub fn new() -> App {
App {
domain_input: String::new(),
whois_info: vec![],
dns_info: vec![],
render_direction: AppRenderDir::Horizontal,
current_state: CurrentState::Lookup,
}
}
}
+96 -27
View File
@@ -7,38 +7,107 @@ use crate::config::Config;
mod whois;
use crate::whois::WhoisData;
use std::io;
use std::io::Write;
mod app;
use crate::app::*;
fn main() {
// let mut running = true;
mod ui;
use crate::ui::*;
use crossterm::event::{
self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode, KeyEventKind,
};
use crossterm::execute;
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use ratatui::backend::{Backend, CrosstermBackend};
use ratatui::Terminal;
use std::error::Error;
use std::io::Write;
use std::io::{self, stderr};
fn main() -> Result<(), Box<dyn Error>> {
enable_raw_mode()?;
let mut stderr = stderr();
execute!(stderr, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stderr);
let mut terminal = Terminal::new(backend)?;
// Initialise the App and config
let mut app = App::new();
let config = Config::from_file("test.ini".to_string());
// Run the app
let res = run_app(&mut terminal, &mut app, &config);
disable_raw_mode()?;
execute!(
terminal.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
terminal.show_cursor()?;
// Clear screen
// print!("{}[2J", 27 as char);
//
// loop {
// let mut domain = String::new();
// print!("Enter domain name: ");
// io::stdout().flush().expect("Failed to flush buffer");
// match io::stdin().read_line(&mut domain) {
// Ok(_n) => {
// domain = String::from(domain.trim());
// match domain.as_ref() {
// "q" => break,
// "" => continue,
// _ => {
// let mut dns = Domain::new(domain.clone());
// dns.apply_config(&config);
// dns.lookup_all_records();
// let whois = WhoisData::new(domain);
// println!("DNS: {}\n\n\nWhois: {}", dns, whois); // Replace this with fancy UI render update command
// }
// }
// }
// Err(err) => {
// println!("{}", err);
// }
// }
// }
Ok(())
}
fn run_app<B: Backend>(
terminal: &mut Terminal<B>,
app: &mut App,
config: &Config,
) -> io::Result<bool> {
loop {
let mut domain = String::new();
print!("Enter domain name: ");
io::stdout().flush().expect("Failed to flush buffer");
match io::stdin().read_line(&mut domain) {
Ok(_n) => {
if domain.trim() == "q" {
break;
}
let mut dns = Domain::new(String::from(domain.trim()));
dns.apply_config(&config);
dns.lookup_all_records();
let whois = WhoisData::new(String::from(domain.trim()));
println!("DNS: {}\n\n\nWhois: {}", dns, whois);
terminal.draw(|f| ui(f, app))?;
if let Event::Key(key) = event::read()? {
if key.kind == event::KeyEventKind::Release {
continue;
}
Err(err) => {
println!("{}", err);
match app.current_state {
CurrentState::Lookup => match key.code {
KeyCode::Esc => return Ok(false),
KeyCode::Backspace => {
app.domain_input.pop();
}
KeyCode::Char(char) => {
app.domain_input.push(char);
}
KeyCode::Enter => {
// This will do the lookup and populate the UI with the info
let mut domain = Domain::new(app.domain_input.clone());
domain.lookup_all_records();
}
_ => {}
},
CurrentState::Menu => {}
}
}
}
// let mut test = Domain::new("ventraip.com.au".to_string());
// let config = Config::from_file("test.ini".to_string());
// test.apply_config(&config);
// test.lookup_all_records();
// let whois = WhoisData::new(test.domain_name.clone());
// println!("Domain: {}\n{}", test.domain_name.clone(), whois);
}
+126
View File
@@ -0,0 +1,126 @@
use ratatui::{
layout::{Constraint, Direction, Layout, Rect},
style::{Color, Style, Styled},
text::{Line, Span, Text},
widgets::{Block, Borders, Clear, List, ListItem, Paragraph, Wrap},
Frame,
};
use crate::{
app::{App, AppRenderDir},
CurrentState,
};
pub fn ui(f: &mut Frame, app: &App) {
match app.current_state {
CurrentState::Lookup => {
match app.render_direction {
/*
Initial contianer is vertical but we have the large center Rect that we will split horizontally
Constraint 1: 30px title bar
Constraint 2: Rest of unused space
Constraint 3: 30px input / key hints
Constraint 2.a: 50% of usable space for whois
Constraint 2.b: 50% of usable space for dns
*/
AppRenderDir::Horizontal => {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3),
Constraint::Min(1),
Constraint::Length(3),
])
.split(f.size());
let title_block = Block::default()
.borders(Borders::ALL)
.style(Style::default());
let title = Paragraph::new(Span::styled(
"Dns Lookup tool",
Style::default().fg(Color::White),
))
.block(title_block);
f.render_widget(title, chunks[0]);
let data_layout = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(chunks[1]);
let whois_block = Block::default()
.borders(Borders::RIGHT)
.style(Style::default());
let whois_text = Paragraph::new(Text::styled(
"Whois data in
style
with
multiline support",
Style::default().fg(Color::Green),
))
.block(whois_block);
f.render_widget(whois_text, data_layout[0]);
let dns_block = Block::default().style(Style::default());
let dns_text = Paragraph::new(Text::styled(
"Dns records
also
with
multiline
support",
Style::default().fg(Color::Red),
))
.block(dns_block);
f.render_widget(dns_text, data_layout[1]);
let footer_chunks = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)])
.split(chunks[2]);
let domain_block = Block::new().borders(Borders::ALL).style(Style::default());
let mut domain_string = String::from("Domain: ");
domain_string.push_str(&app.domain_input);
let domain_text = Paragraph::new(Text::styled(
domain_string,
Style::default().fg(Color::Blue),
))
.block(domain_block);
f.render_widget(domain_text, footer_chunks[0]);
let key_hint_block = Block::default()
.borders(Borders::ALL)
.style(Style::default());
let key_hint = Paragraph::new(Text::styled(
"[ESC] Quit / [Enter] Check domain",
Style::default().fg(Color::Red),
))
.block(key_hint_block);
f.render_widget(key_hint, footer_chunks[1]);
}
/*
Constraint 1: 30px title bar
Constraint 2: 50% of unused space for whois
Constraint 3: 50% of unused space for dns
Constraint 4: 30px input / key hints
*/
AppRenderDir::Vertical => {
let chunks = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Max(30),
Constraint::Percentage(50),
Constraint::Percentage(50),
Constraint::Max(30),
])
.split(f.size());
}
}
}
CurrentState::Menu => {}
}
}