initial page: add picklist to select capture source

This commit is contained in:
GyulyVGC
2025-08-16 16:30:57 +02:00
parent f5d689ad7b
commit ee175b6a43
7 changed files with 134 additions and 76 deletions

View File

@@ -15,14 +15,14 @@
use crate::gui::types::export_pcap::ExportPcap;
use crate::gui::types::filters::Filters;
use crate::gui::types::message::Message;
use crate::networking::types::capture_context::CaptureSource;
use crate::networking::types::capture_context::{CaptureSource, CaptureSourcePicklist};
use crate::translations::translations::{
address_translation, addresses_translation, choose_adapters_translation, start_translation,
address_translation, addresses_translation, network_adapter_translation, start_translation,
};
use crate::translations::translations_3::{
directory_translation, export_capture_translation, file_name_translation,
};
use crate::translations::translations_4::import_capture_translation;
use crate::translations::translations_4::capture_file_translation;
use crate::translations::translations_5::{filter_traffic_translation, traffic_source_translation};
use crate::utils::formatted_strings::get_path_termination_string;
use crate::utils::types::file_info::FileInfo;
@@ -30,10 +30,9 @@
use crate::{ConfigSettings, Language, StyleType};
use iced::Length::FillPortion;
use iced::widget::scrollable::Direction;
use iced::widget::tooltip::Position;
use iced::widget::{
Button, Checkbox, Column, Container, PickList, Row, Rule, Scrollable, Space, Text, TextInput,
Tooltip, button, center, vertical_space,
Button, Checkbox, Column, Container, PickList, Row, Scrollable, Space, Text, TextInput, button,
center, vertical_space,
};
use iced::{Alignment, Font, Length, Padding, alignment};
@@ -52,21 +51,27 @@ pub fn initial_page(sniffer: &Sniffer) -> Container<'_, Message, StyleType> {
let col_checkboxes = Column::new()
.spacing(10)
.push(Space::with_height(82))
.push(Space::with_height(66))
.push(get_filters_group(&sniffer.filters, font, language))
.push_maybe(get_export_pcap_group_maybe(
&sniffer.capture_source,
sniffer.capture_source_picklist,
&sniffer.export_pcap,
language,
font,
));
let is_capture_source_consistent = sniffer.is_capture_source_consistent();
let right_col = Column::new()
.width(FillPortion(1))
.padding(10)
.push(col_checkboxes)
.push(vertical_space())
.push(button_start(font_headers, language, color_gradient))
.push(button_start(
font_headers,
language,
color_gradient,
is_capture_source_consistent,
))
.push(vertical_space());
let body = Column::new().push(Space::with_height(5)).push(
@@ -83,6 +88,7 @@ fn button_start<'a>(
font_headers: Font,
language: Language,
color_gradient: GradientType,
is_capture_source_consistent: bool,
) -> Button<'a, Message, StyleType> {
button(
Text::new(start_translation(language))
@@ -95,7 +101,11 @@ fn button_start<'a>(
.padding(15)
.width(Length::Fill)
.class(ButtonType::Gradient(color_gradient))
.on_press(Message::Start)
.on_press_maybe(if is_capture_source_consistent {
Some(Message::Start)
} else {
None
})
}
fn get_col_data_source(
@@ -103,33 +113,51 @@ fn get_col_data_source(
font: Font,
language: Language,
) -> Column<'_, Message, StyleType> {
let current_option = if sniffer.capture_source_picklist == CaptureSourcePicklist::Device {
network_adapter_translation(language)
} else {
capture_file_translation(language)
};
let picklist = PickList::new(
&Language::ALL[..],
Some(language),
Message::LanguageSelection,
[
network_adapter_translation(language),
capture_file_translation(language),
],
Some(current_option),
move |option| {
if option == network_adapter_translation(language) {
Message::SetCaptureSource(CaptureSourcePicklist::Device)
} else {
Message::SetCaptureSource(CaptureSourcePicklist::File)
}
},
)
.padding([2, 7])
.font(font);
let mut col = Column::new()
.align_x(Alignment::Center)
.padding(10)
.spacing(20)
.padding(Padding::new(10.0).top(30))
.spacing(30)
.height(Length::Fill)
.width(FillPortion(1))
.push(
Text::new(traffic_source_translation(language))
.font(font)
.class(TextType::Title)
.size(FONT_SIZE_TITLE),
)
.push(picklist);
Row::new()
.spacing(10)
.push(
Text::new(traffic_source_translation(language))
.font(font)
.class(TextType::Title)
.size(FONT_SIZE_TITLE),
)
.push(picklist),
);
match &sniffer.capture_source {
CaptureSource::Device(_) => {
match &sniffer.capture_source_picklist {
CaptureSourcePicklist::Device => {
col = col.push(get_col_adapter(sniffer, font, language));
}
CaptureSource::File(_) => {
CaptureSourcePicklist::File => {
col = col.push(get_col_import_pcap(
language,
font,
@@ -261,6 +289,7 @@ fn get_col_import_pcap<'a>(
let content = Column::new()
.width(Length::Fill)
.align_x(alignment::Alignment::Center)
.spacing(5)
.push(button_row);
@@ -321,12 +350,12 @@ fn get_filters_group<'a>(
}
fn get_export_pcap_group_maybe<'a>(
cs: &CaptureSource,
cs_pick: CaptureSourcePicklist,
export_pcap: &ExportPcap,
language: Language,
font: Font,
) -> Option<Container<'a, Message, StyleType>> {
if matches!(cs, CaptureSource::File(_)) {
if cs_pick == CaptureSourcePicklist::File {
return None;
}

View File

@@ -46,7 +46,9 @@
use crate::mmdb::types::mmdb_reader::{MmdbReader, MmdbReaders};
use crate::networking::parse_packets::BackendTrafficMessage;
use crate::networking::parse_packets::parse_packets;
use crate::networking::types::capture_context::{CaptureContext, CaptureSource, MyPcapImport};
use crate::networking::types::capture_context::{
CaptureContext, CaptureSource, CaptureSourcePicklist, MyPcapImport,
};
use crate::networking::types::data_representation::DataRepr;
use crate::networking::types::host::{Host, HostMessage};
use crate::networking::types::host_data_states::HostDataStates;
@@ -88,6 +90,8 @@ pub struct Sniffer {
pub logged_notifications: (VecDeque<LoggedNotification>, usize),
/// Reports if a newer release of the software is available on GitHub
pub newer_release_available: Option<bool>,
/// Capture source picklist, to select the source of the capture
pub capture_source_picklist: CaptureSourcePicklist,
/// Network device to be analyzed, or PCAP file to be imported
pub capture_source: CaptureSource,
/// List of network devices
@@ -154,6 +158,7 @@ pub fn new(configs: Configs) -> Self {
favorite_hosts: HashSet::new(),
logged_notifications: (VecDeque::new(), 0),
newer_release_available: None,
capture_source_picklist: CaptureSourcePicklist::default(),
capture_source: CaptureSource::Device(device),
my_devices: Vec::new(),
filters: Filters::default(),
@@ -277,6 +282,16 @@ pub fn update(&mut self, message: Message) -> Task<Message> {
}
}
Message::DeviceSelection(name) => self.set_device(&name),
Message::SetCaptureSource(cs_pick) => {
self.capture_source_picklist = cs_pick;
return if cs_pick == CaptureSourcePicklist::File {
Task::done(Message::SetPcapImport(self.import_pcap_path.clone()))
} else {
Task::done(Message::DeviceSelection(
self.configs.device.device_name.clone(),
))
};
}
Message::ToggleFilters => {
self.filters.toggle();
}
@@ -289,7 +304,11 @@ pub fn update(&mut self, message: Message) -> Task<Message> {
self.report_sort_type = sort;
}
Message::OpenWebPage(web_page) => Self::open_web(&web_page),
Message::Start => return self.start(),
Message::Start => {
if self.is_capture_source_consistent() {
return self.start();
}
}
Message::Reset => self.reset(),
Message::Style(style) => {
self.configs.settings.style = style;
@@ -680,14 +699,6 @@ fn refresh_data(&mut self, mut msg: InfoTraffic, no_more_packets: bool) {
}
self.traffic_chart.update_charts_data(&msg, no_more_packets);
if let CaptureSource::Device(device) = &self.capture_source {
let current_device_name = device.get_name().clone();
// update ConfigDevice stored if different from last sniffed device
let last_device_name_sniffed = self.configs.device.device_name.clone();
if current_device_name.ne(&last_device_name_sniffed) {
self.configs.device.device_name = current_device_name;
}
}
// update host dropdowns
self.host_data_states.update_states(&self.search);
}
@@ -792,6 +803,7 @@ fn reset(&mut self) {
fn set_device(&mut self, name: &str) {
for my_dev in &self.my_devices {
if my_dev.get_name().eq(&name) {
self.configs.device.device_name = name.to_string();
self.capture_source = CaptureSource::Device(my_dev.clone());
break;
}
@@ -1069,6 +1081,13 @@ fn register_sigint_handler() -> Task<Message> {
Task::run(rx, |()| Message::Quit)
}
pub fn is_capture_source_consistent(&self) -> bool {
self.capture_source_picklist == CaptureSourcePicklist::Device
&& matches!(self.capture_source, CaptureSource::Device(_))
|| self.capture_source_picklist == CaptureSourcePicklist::File
&& matches!(self.capture_source, CaptureSource::File(_))
}
}
#[cfg(test)]

View File

@@ -216,7 +216,7 @@ fn disabled(&self, style: &StyleType) -> Style {
},
},
text_color: Color {
a: ext.alpha_chart_badge,
a: 0.5,
..colors.text_headers
},
shadow: Shadow::default(),

View File

@@ -5,6 +5,7 @@
use crate::gui::pages::types::running_page::RunningPage;
use crate::gui::pages::types::settings_page::SettingsPage;
use crate::gui::styles::types::gradient_type::GradientType;
use crate::networking::types::capture_context::CaptureSourcePicklist;
use crate::networking::types::data_representation::DataRepr;
use crate::networking::types::host::{Host, HostMessage};
use crate::networking::types::info_traffic::InfoTraffic;
@@ -22,6 +23,8 @@ pub enum Message {
StartApp(Option<window::Id>),
/// Sent by the backend parsing packets; includes the capture id, new data, new hosts batched data, and whether an offline capture has finished
TickRun(usize, InfoTraffic, Vec<HostMessage>, bool),
/// Capture source selected from the picklist
SetCaptureSource(CaptureSourcePicklist),
/// Select network device
DeviceSelection(String),
/// Toggle BPF filter checkbox

View File

@@ -2,7 +2,7 @@
use crate::networking::types::my_device::MyDevice;
use crate::networking::types::my_link_type::MyLinkType;
use crate::translations::translations::network_adapter_translation;
use crate::translations::translations_3::file_name_translation;
use crate::translations::translations_4::capture_file_translation;
use crate::translations::types::language::Language;
use pcap::{Active, Address, Capture, Error, Packet, Savefile, Stat};
@@ -158,7 +158,7 @@ impl CaptureSource {
pub fn title(&self, language: Language) -> &str {
match self {
Self::Device(_) => network_adapter_translation(language),
Self::File(_) => file_name_translation(language),
Self::File(_) => capture_file_translation(language),
}
}
@@ -221,3 +221,10 @@ pub fn new(path: String) -> Self {
}
}
}
#[derive(Clone, Eq, PartialEq, Debug, Copy, Default)]
pub enum CaptureSourcePicklist {
#[default]
Device,
File,
}

View File

@@ -5,33 +5,33 @@
use crate::StyleType;
use crate::translations::types::language::Language;
pub fn choose_adapters_translation<'a>(language: Language) -> Text<'a, StyleType> {
Text::new(match language {
Language::EN => "Select network adapter to inspect",
Language::IT => "Seleziona la scheda di rete da ispezionare",
Language::FR => "Sélectionnez une carte réseau à inspecter",
Language::ES => "Seleccione el adaptador de red que desea inspeccionar",
Language::PL => "Wybierz adapter sieciowy do inspekcji",
Language::DE => "Wähle einen Netzwerkadapter zum überwachen aus",
Language::UK => "Виберіть мережевий адаптер для перевірки",
Language::ZH => "选择需要监控的网络适配器",
Language::ZH_TW => "選取要檢視的網路介面卡",
Language::RO => "Selectați adaptor de rețea pentru a inspecta",
Language::KO => "검사할 네트워크 어댑터 선택",
Language::TR => "İncelemek için bir ağ adaptörü seçiniz",
Language::RU => "Выберите сетевой адаптер для инспекции",
Language::PT => "Selecione o adaptador de rede a inspecionar",
Language::EL => "Επίλεξε τον προσαρμογέα δικτύου για επιθεώρηση",
// Language::FA => "مبدل شبکه را برای بازرسی انتخاب کنید",
Language::SV => "Välj nätverksadapter att inspektera",
Language::FI => "Valitse tarkasteltava verkkosovitin",
Language::JA => "使用するネットワーク アダプターを選択してください",
Language::UZ => "Tekshirish uchun tarmoq adapterini tanlang",
Language::VI => "Hãy chọn network adapter để quan sát",
Language::ID => "Pilih Adapter Jaringan yang ingin dicek",
Language::NL => "Selecteer netwerkadapter om te inspecteren",
})
}
// pub fn choose_adapters_translation<'a>(language: Language) -> Text<'a, StyleType> {
// Text::new(match language {
// Language::EN => "Select network adapter to inspect",
// Language::IT => "Seleziona la scheda di rete da ispezionare",
// Language::FR => "Sélectionnez une carte réseau à inspecter",
// Language::ES => "Seleccione el adaptador de red que desea inspeccionar",
// Language::PL => "Wybierz adapter sieciowy do inspekcji",
// Language::DE => "Wähle einen Netzwerkadapter zum überwachen aus",
// Language::UK => "Виберіть мережевий адаптер для перевірки",
// Language::ZH => "选择需要监控的网络适配器",
// Language::ZH_TW => "選取要檢視的網路介面卡",
// Language::RO => "Selectați adaptor de rețea pentru a inspecta",
// Language::KO => "검사할 네트워크 어댑터 선택",
// Language::TR => "İncelemek için bir ağ adaptörü seçiniz",
// Language::RU => "Выберите сетевой адаптер для инспекции",
// Language::PT => "Selecione o adaptador de rede a inspecionar",
// Language::EL => "Επίλεξε τον προσαρμογέα δικτύου για επιθεώρηση",
// // Language::FA => "مبدل شبکه را برای بازرسی انتخاب کنید",
// Language::SV => "Välj nätverksadapter att inspektera",
// Language::FI => "Valitse tarkasteltava verkkosovitin",
// Language::JA => "使用するネットワーク アダプターを選択してください",
// Language::UZ => "Tekshirish uchun tarmoq adapterini tanlang",
// Language::VI => "Hãy chọn network adapter để quan sát",
// Language::ID => "Pilih Adapter Jaringan yang ingin dicek",
// Language::NL => "Selecteer netwerkadapter om te inspecteren",
// })
// }
// pub fn application_protocol_translation(language: Language) -> &'static str {
// match language {

View File

@@ -53,17 +53,17 @@ pub fn share_feedback_translation(language: Language) -> &'static str {
// }
// }
pub fn import_capture_translation(language: Language) -> &'static str {
pub fn capture_file_translation(language: Language) -> &'static str {
match language {
Language::EN => "Import capture file",
Language::IT => "Importa file di cattura",
Language::FR => "Importer un fichier de capture",
Language::JA => "キャプチャファイルをインポート",
Language::ZH => "导入捕获文件",
Language::NL => "Importeer capture bestand",
Language::DE => "Aufzeichnungsdatei importieren",
Language::UZ => "Tahlil faylini import qilish",
_ => "Import capture file",
Language::EN => "Capture file",
Language::IT => "File di cattura",
Language::FR => "Fichier de capture",
Language::JA => "キャプチャファイル",
Language::ZH => "捕获文件",
Language::NL => "Capture bestand",
Language::DE => "Aufzeichnungsdatei",
Language::UZ => "Tahlil faylini",
_ => "Capture file",
}
}