mirror of
https://github.com/GyulyVGC/sniffnet.git
synced 2025-12-23 22:29:01 -05:00
implemented possibility to copy IPs from connection details page
This commit is contained in:
Binary file not shown.
@@ -14,6 +14,7 @@
|
||||
use crate::gui::styles::text::TextType;
|
||||
use crate::gui::styles::types::gradient_type::GradientType;
|
||||
use crate::gui::types::message::Message;
|
||||
use crate::gui::types::timing_events::TimingEvents;
|
||||
use crate::networking::manage_packets::{get_address_to_lookup, get_traffic_type, is_my_address};
|
||||
use crate::networking::types::address_port_pair::AddressPortPair;
|
||||
use crate::networking::types::host::Host;
|
||||
@@ -28,6 +29,7 @@
|
||||
fqdn_translation, mac_address_translation, socket_address_translation, source_translation,
|
||||
transmitted_data_translation,
|
||||
};
|
||||
use crate::translations::translations_3::copy_translation;
|
||||
use crate::utils::formatted_strings::{get_formatted_bytes_string_with_b, get_socket_address};
|
||||
use crate::utils::types::icon::Icon;
|
||||
use crate::{Language, Sniffer, StyleType};
|
||||
@@ -37,7 +39,11 @@ pub fn connection_details_page(
|
||||
key: AddressPortPair,
|
||||
) -> Container<Message, Renderer<StyleType>> {
|
||||
Container::new(lazy(
|
||||
sniffer.runtime_data.tot_sent_packets + sniffer.runtime_data.tot_received_packets,
|
||||
(
|
||||
sniffer.runtime_data.tot_sent_packets + sniffer.runtime_data.tot_received_packets,
|
||||
sniffer.timing_events.was_just_copy_ip(&key.address1),
|
||||
sniffer.timing_events.was_just_copy_ip(&key.address2),
|
||||
),
|
||||
move |_| page_content(sniffer, &key),
|
||||
))
|
||||
}
|
||||
@@ -116,6 +122,7 @@ fn page_content(
|
||||
&val.mac_address1,
|
||||
font,
|
||||
language,
|
||||
&sniffer.timing_events,
|
||||
);
|
||||
let mut dest_col = get_src_or_dest_col(
|
||||
dest_caption,
|
||||
@@ -124,6 +131,7 @@ fn page_content(
|
||||
&val.mac_address2,
|
||||
font,
|
||||
language,
|
||||
&sniffer.timing_events,
|
||||
);
|
||||
|
||||
if address_to_lookup.eq(&key.address1) {
|
||||
@@ -308,6 +316,7 @@ fn get_src_or_dest_col(
|
||||
mac: &str,
|
||||
font: Font,
|
||||
language: Language,
|
||||
timing_events: &TimingEvents,
|
||||
) -> Column<'static, Message, Renderer<StyleType>> {
|
||||
Column::new()
|
||||
.spacing(4)
|
||||
@@ -317,11 +326,17 @@ fn get_src_or_dest_col(
|
||||
.align_x(Horizontal::Center),
|
||||
)
|
||||
.push(Rule::horizontal(10.0))
|
||||
.push(TextType::highlighted_subtitle_with_desc(
|
||||
socket_address_translation(language),
|
||||
&get_socket_address(ip, port),
|
||||
font,
|
||||
))
|
||||
.push(
|
||||
Row::new()
|
||||
.spacing(10)
|
||||
.align_items(Alignment::End)
|
||||
.push(TextType::highlighted_subtitle_with_desc(
|
||||
socket_address_translation(language),
|
||||
&get_socket_address(ip, port),
|
||||
font,
|
||||
))
|
||||
.push(get_button_copy(language, font, ip, timing_events)),
|
||||
)
|
||||
.push(TextType::highlighted_subtitle_with_desc(
|
||||
mac_address_translation(language),
|
||||
mac,
|
||||
@@ -359,3 +374,33 @@ fn assemble_widgets(
|
||||
.push(vertical_space(Length::FillPortion(1))),
|
||||
)
|
||||
}
|
||||
|
||||
fn get_button_copy(
|
||||
language: Language,
|
||||
font: Font,
|
||||
string: &String,
|
||||
timing_events: &TimingEvents,
|
||||
) -> Tooltip<'static, Message, Renderer<StyleType>> {
|
||||
let icon = if timing_events.was_just_copy_ip(string) {
|
||||
Text::new("✔").font(font).size(14)
|
||||
} else {
|
||||
Icon::Copy.to_text().size(12)
|
||||
};
|
||||
|
||||
let content = button(
|
||||
icon.horizontal_alignment(Horizontal::Center)
|
||||
.vertical_alignment(Vertical::Center),
|
||||
)
|
||||
.padding(0)
|
||||
.height(Length::Fixed(25.0))
|
||||
.width(Length::Fixed(25.0))
|
||||
.on_press(Message::CopyIp(string.clone()));
|
||||
|
||||
Tooltip::new(
|
||||
content,
|
||||
format!("{} (IP)", copy_translation(language)),
|
||||
Position::Right,
|
||||
)
|
||||
.font(font)
|
||||
.style(ContainerType::Tooltip)
|
||||
}
|
||||
|
||||
@@ -103,4 +103,6 @@ pub enum Message {
|
||||
// CustomReport(String),
|
||||
/// Save the configurations of the app and quit
|
||||
CloseRequested,
|
||||
/// Copies the given string to clipboard
|
||||
CopyIp(String),
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod message;
|
||||
pub mod runtime_data;
|
||||
pub mod sniffer;
|
||||
pub mod timing_events;
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use std::collections::{HashSet, VecDeque};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use iced::{window, Command};
|
||||
use pcap::Device;
|
||||
@@ -16,6 +15,7 @@
|
||||
use crate::gui::pages::types::settings_page::SettingsPage;
|
||||
use crate::gui::styles::types::custom_palette::{CustomPalette, ExtraStyles};
|
||||
use crate::gui::types::message::Message;
|
||||
use crate::gui::types::timing_events::TimingEvents;
|
||||
use crate::mmdb::asn::ASN_MMDB;
|
||||
use crate::mmdb::country::COUNTRY_MMDB;
|
||||
use crate::mmdb::types::mmdb_reader::MmdbReader;
|
||||
@@ -75,8 +75,6 @@ pub struct Sniffer {
|
||||
pub search: SearchParameters,
|
||||
/// Current page number of inspect search results
|
||||
pub page_number: usize,
|
||||
/// Record the timestamp of last window focus
|
||||
pub last_focus_time: std::time::Instant,
|
||||
/// Application settings
|
||||
pub settings: ConfigSettings,
|
||||
/// Position and size of the app window
|
||||
@@ -85,6 +83,8 @@ pub struct Sniffer {
|
||||
pub country_mmdb_reader: Arc<MmdbReader>,
|
||||
/// MMDB reader for ASN
|
||||
pub asn_mmdb_reader: Arc<MmdbReader>,
|
||||
/// Time-related events
|
||||
pub timing_events: TimingEvents,
|
||||
}
|
||||
|
||||
impl Sniffer {
|
||||
@@ -108,7 +108,6 @@ pub fn new(configs: &Configs, newer_release_available: Arc<Mutex<Option<bool>>>)
|
||||
unread_notifications: 0,
|
||||
search: SearchParameters::default(),
|
||||
page_number: 1,
|
||||
last_focus_time: std::time::Instant::now(),
|
||||
settings: configs.settings.clone(),
|
||||
window: configs.window,
|
||||
country_mmdb_reader: Arc::new(MmdbReader::from(
|
||||
@@ -116,6 +115,7 @@ pub fn new(configs: &Configs, newer_release_available: Arc<Mutex<Option<bool>>>)
|
||||
COUNTRY_MMDB,
|
||||
)),
|
||||
asn_mmdb_reader: Arc::new(MmdbReader::from(&configs.settings.mmdb_asn, ASN_MMDB)),
|
||||
timing_events: TimingEvents::default(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,7 +196,7 @@ pub fn update(&mut self, message: Message) -> Command<Message> {
|
||||
Message::SwitchPage(next) => {
|
||||
// To prevent SwitchPage be triggered when using `Alt` + `Tab` to switch back,
|
||||
// first check if user switch back just now, and ignore the request for a short time.
|
||||
if self.last_focus_time.elapsed() > Duration::from_millis(200) {
|
||||
if !self.timing_events.was_just_focus() {
|
||||
self.switch_page(next);
|
||||
}
|
||||
}
|
||||
@@ -232,7 +232,7 @@ pub fn update(&mut self, message: Message) -> Command<Message> {
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::WindowFocused => self.last_focus_time = std::time::Instant::now(),
|
||||
Message::WindowFocused => self.timing_events.focus_now(),
|
||||
Message::GradientsSelection(gradient_type) => {
|
||||
self.settings.color_gradient = gradient_type;
|
||||
}
|
||||
@@ -263,6 +263,10 @@ pub fn update(&mut self, message: Message) -> Command<Message> {
|
||||
self.get_configs().store();
|
||||
return iced::window::close();
|
||||
}
|
||||
Message::CopyIp(string) => {
|
||||
self.timing_events.copy_ip_now(string.clone());
|
||||
return iced::clipboard::write(string);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
Command::none()
|
||||
@@ -1119,9 +1123,9 @@ fn test_clear_all_notifications() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_correctly_switch_running_and_notification_pages() {
|
||||
fn test_correctly_switch_running_and_settings_pages() {
|
||||
let mut sniffer = Sniffer::new(&Configs::default(), Arc::new(Mutex::new(None)));
|
||||
sniffer.last_focus_time = std::time::Instant::now().sub(Duration::from_millis(400));
|
||||
sniffer.timing_events.focus = std::time::Instant::now().sub(Duration::from_millis(400));
|
||||
|
||||
// initial status
|
||||
assert_eq!(sniffer.settings_page, None);
|
||||
|
||||
39
src/gui/types/timing_events.rs
Normal file
39
src/gui/types/timing_events.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct TimingEvents {
|
||||
/// Timestamp of last window focus
|
||||
pub focus: std::time::Instant,
|
||||
/// Timestamp of the last press on Copy IP button, with the related IP address
|
||||
pub copy_ip: (std::time::Instant, String),
|
||||
}
|
||||
|
||||
impl TimingEvents {
|
||||
const TIMEOUT_FOCUS: u64 = 200;
|
||||
const TIMEOUT_COPY_IP: u64 = 1500;
|
||||
|
||||
pub fn focus_now(&mut self) {
|
||||
self.focus = std::time::Instant::now();
|
||||
}
|
||||
|
||||
pub fn was_just_focus(&self) -> bool {
|
||||
self.focus.elapsed() < Duration::from_millis(TimingEvents::TIMEOUT_FOCUS)
|
||||
}
|
||||
|
||||
pub fn copy_ip_now(&mut self, ip: String) {
|
||||
self.copy_ip = (std::time::Instant::now(), ip);
|
||||
}
|
||||
|
||||
pub fn was_just_copy_ip(&self, ip: &String) -> bool {
|
||||
self.copy_ip.0.elapsed() < Duration::from_millis(TimingEvents::TIMEOUT_COPY_IP)
|
||||
&& self.copy_ip.1.eq(ip)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for TimingEvents {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
focus: std::time::Instant::now(),
|
||||
copy_ip: (std::time::Instant::now(), String::new()),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -49,3 +49,11 @@ pub fn custom_style_translation(language: Language) -> &'static str {
|
||||
_ => "Custom style",
|
||||
}
|
||||
}
|
||||
|
||||
pub fn copy_translation(language: Language) -> &'static str {
|
||||
match language {
|
||||
Language::EN => "Copy",
|
||||
Language::IT => "Copia",
|
||||
_ => "Copy",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ pub enum Icon {
|
||||
Bin,
|
||||
BytesThreshold,
|
||||
Clock,
|
||||
Copy,
|
||||
Dots,
|
||||
Error,
|
||||
// File,
|
||||
@@ -74,6 +75,7 @@ pub fn to_text(&self) -> iced::advanced::widget::Text<'static, Renderer<StyleTyp
|
||||
Icon::Star => "g",
|
||||
Icon::Warning => "T",
|
||||
Icon::Waves => "y",
|
||||
Icon::Copy => "u",
|
||||
})
|
||||
.font(ICONS)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user