mirror of
https://github.com/GyulyVGC/sniffnet.git
synced 2026-10-23 23:51:18 +00:00
commit
54e47a093a
8 changed files with 120 additions and 6 deletions
|
|
@ -2,6 +2,9 @@
|
|||
|
||||
All Sniffnet releases with the relative changes are documented in this file.
|
||||
|
||||
## [UNRELEASED]
|
||||
- Add animated welcome screen ([#1002](https://github.com/GyulyVGC/sniffnet/pull/1002))
|
||||
|
||||
## [1.4.2] - 2025-11-04
|
||||
- Send remote notifications via webhook ([#991](https://github.com/GyulyVGC/sniffnet/pull/991) — fixes [#841](https://github.com/GyulyVGC/sniffnet/issues/841))
|
||||
- Pause and resume packet captures ([#992](https://github.com/GyulyVGC/sniffnet/pull/992) — fixes [#551](https://github.com/GyulyVGC/sniffnet/issues/551))
|
||||
|
|
|
|||
Binary file not shown.
|
|
@ -8,3 +8,4 @@ pub mod settings_notifications_page;
|
|||
pub mod settings_style_page;
|
||||
pub mod thumbnail_page;
|
||||
pub mod types;
|
||||
pub mod welcome_page;
|
||||
|
|
|
|||
55
src/gui/pages/welcome_page.rs
Normal file
55
src/gui/pages/welcome_page.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use crate::StyleType;
|
||||
use crate::gui::styles::text::TextType;
|
||||
use crate::gui::types::message::Message;
|
||||
use crate::utils::types::icon::Icon;
|
||||
use iced::alignment::{Horizontal, Vertical};
|
||||
use iced::widget::{Column, Container, Space, Text, vertical_space};
|
||||
use iced::{Alignment, Font, Length};
|
||||
|
||||
pub fn welcome_page<'a>(font: Font, x: u8) -> Container<'a, Message, StyleType> {
|
||||
let icon = match x {
|
||||
0..=3 | 20.. => Text::new(""),
|
||||
4 => Icon::Sniffnet1.to_text(),
|
||||
5 => Icon::Sniffnet2.to_text(),
|
||||
6 => Icon::Sniffnet3.to_text(),
|
||||
7 => Icon::Sniffnet4.to_text(),
|
||||
8..=19 => Icon::Sniffnet.to_text(),
|
||||
};
|
||||
|
||||
let text = Text::new(match x {
|
||||
0..=3 | 20.. => "",
|
||||
4 => "S",
|
||||
5 => "Sn",
|
||||
6 => "Sni",
|
||||
7 => "Snif",
|
||||
8 => "Sniff",
|
||||
9 => "Sniffn",
|
||||
10 => "Sniffne",
|
||||
11..=19 => "Sniffnet",
|
||||
});
|
||||
|
||||
let text_type = match x {
|
||||
0..=3 | 20.. => TextType::Welcome(0.0),
|
||||
4 => TextType::Welcome(0.125),
|
||||
5 => TextType::Welcome(0.25),
|
||||
6 => TextType::Welcome(0.375),
|
||||
7 => TextType::Welcome(0.5),
|
||||
8 => TextType::Welcome(0.625),
|
||||
9 => TextType::Welcome(0.750),
|
||||
10 => TextType::Welcome(0.875),
|
||||
11..=19 => TextType::Welcome(1.0),
|
||||
};
|
||||
|
||||
let body = Column::new()
|
||||
.align_x(Alignment::Center)
|
||||
.push(vertical_space())
|
||||
.push(icon.size(200).line_height(0.9).class(text_type))
|
||||
.push(text.font(font).size(75).class(text_type))
|
||||
.push(Space::with_height(Length::FillPortion(2)));
|
||||
|
||||
Container::new(body)
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.align_x(Horizontal::Center)
|
||||
.align_y(Vertical::Center)
|
||||
}
|
||||
|
|
@ -33,6 +33,7 @@ use crate::gui::pages::settings_style_page::settings_style_page;
|
|||
use crate::gui::pages::thumbnail_page::thumbnail_page;
|
||||
use crate::gui::pages::types::running_page::RunningPage;
|
||||
use crate::gui::pages::types::settings_page::SettingsPage;
|
||||
use crate::gui::pages::welcome_page::welcome_page;
|
||||
use crate::gui::styles::types::custom_palette::{CustomPalette, ExtraStyles};
|
||||
use crate::gui::styles::types::palette::Palette;
|
||||
use crate::gui::types::conf::Conf;
|
||||
|
|
@ -77,6 +78,8 @@ pub const ICON_FONT_FAMILY_NAME: &str = "Icons for Sniffnet";
|
|||
pub struct Sniffer {
|
||||
/// Parameters that are persistent across runs
|
||||
pub conf: Conf,
|
||||
/// Are we during welcome / quit animation? None if not, true if welcome, false if quit
|
||||
pub welcome: Option<(bool, u8)>,
|
||||
/// Capture receiver clone (to close the channel after every run), with the current capture id (to ignore pending messages from previous captures)
|
||||
pub current_capture_rx: (usize, Option<Receiver<BackendTrafficMessage>>),
|
||||
/// Capture data
|
||||
|
|
@ -140,6 +143,7 @@ impl Sniffer {
|
|||
let capture_source = CaptureSource::from_conf(&conf);
|
||||
Self {
|
||||
conf,
|
||||
welcome: Some((true, 0)),
|
||||
current_capture_rx: (0, None),
|
||||
info_traffic: InfoTraffic::default(),
|
||||
addresses_resolved: HashMap::new(),
|
||||
|
|
@ -173,6 +177,10 @@ impl Sniffer {
|
|||
fn keyboard_subscription(&self) -> Subscription<Message> {
|
||||
const NO_MODIFIER: Modifiers = Modifiers::empty();
|
||||
|
||||
if self.welcome.is_some() {
|
||||
return Subscription::none();
|
||||
}
|
||||
|
||||
if self.thumbnail {
|
||||
iced::event::listen_with(|event, _, _| match event {
|
||||
Keyboard(Event::KeyPressed {
|
||||
|
|
@ -231,8 +239,17 @@ impl Sniffer {
|
|||
}
|
||||
}
|
||||
|
||||
fn time_subscription() -> Subscription<Message> {
|
||||
iced::time::every(Duration::from_millis(1000)).map(|_| Message::Periodic)
|
||||
fn time_subscription(&self) -> Subscription<Message> {
|
||||
if let Some((w, _)) = self.welcome {
|
||||
let sub = iced::time::every(Duration::from_millis(100));
|
||||
if w {
|
||||
sub.map(|_| Message::Welcome)
|
||||
} else {
|
||||
sub.map(|_| Message::Quit)
|
||||
}
|
||||
} else {
|
||||
iced::time::every(Duration::from_millis(1000)).map(|_| Message::Periodic)
|
||||
}
|
||||
}
|
||||
|
||||
fn window_subscription() -> Subscription<Message> {
|
||||
|
|
@ -430,8 +447,24 @@ impl Sniffer {
|
|||
}
|
||||
Message::QuitWrapper => return self.quit_wrapper(),
|
||||
Message::Quit => {
|
||||
let _ = self.conf.clone().store();
|
||||
return window::close(self.id.unwrap_or_else(Id::unique));
|
||||
if self.welcome.is_none() {
|
||||
self.welcome = Some((false, 13));
|
||||
} else if let Some((false, x)) = self.welcome {
|
||||
if x <= 2 {
|
||||
let _ = self.conf.clone().store();
|
||||
return window::close(self.id.unwrap_or_else(Id::unique));
|
||||
}
|
||||
self.welcome = Some((false, x.saturating_sub(1)));
|
||||
}
|
||||
}
|
||||
Message::Welcome => {
|
||||
if let Some((true, x)) = self.welcome {
|
||||
if x >= 19 {
|
||||
self.welcome = None;
|
||||
} else {
|
||||
self.welcome = Some((true, x + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::CopyIp(ip) => {
|
||||
self.timing_events.copy_ip_now(ip);
|
||||
|
|
@ -595,6 +628,10 @@ impl Sniffer {
|
|||
let font = style.get_extension().font;
|
||||
let font_headers = style.get_extension().font_headers;
|
||||
|
||||
if let Some((_, x)) = self.welcome {
|
||||
return welcome_page(font, x).into();
|
||||
}
|
||||
|
||||
let header = header(self);
|
||||
|
||||
let body = if self.thumbnail {
|
||||
|
|
@ -676,7 +713,7 @@ impl Sniffer {
|
|||
Subscription::batch([
|
||||
self.keyboard_subscription(),
|
||||
self.mouse_subscription(),
|
||||
Sniffer::time_subscription(),
|
||||
self.time_subscription(),
|
||||
Sniffer::window_subscription(),
|
||||
])
|
||||
}
|
||||
|
|
@ -1895,7 +1932,8 @@ mod tests {
|
|||
sniffer.update(Message::ChangeRunningPage(RunningPage::Notifications));
|
||||
sniffer.update(Message::DataReprSelection(DataRepr::Bits));
|
||||
|
||||
// quit the app by sending a CloseRequested message
|
||||
// force saving configs by quitting the app
|
||||
sniffer.welcome = Some((false, 0));
|
||||
sniffer.update(Message::Quit);
|
||||
|
||||
assert!(path.exists());
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ pub enum TextType {
|
|||
Subtitle,
|
||||
Danger,
|
||||
Sponsor,
|
||||
Welcome(f32),
|
||||
}
|
||||
|
||||
/// Returns a formatted caption followed by subtitle, new line, tab, and desc
|
||||
|
|
@ -71,6 +72,12 @@ pub fn highlight(style: &StyleType, element: TextType) -> Color {
|
|||
a: 1.0,
|
||||
}
|
||||
}
|
||||
TextType::Welcome(mut n) => {
|
||||
if !(0.0..=1.0).contains(&n) {
|
||||
n = 1.0;
|
||||
}
|
||||
Color { a: n, ..secondary }
|
||||
}
|
||||
TextType::Incoming => colors.secondary,
|
||||
TextType::Outgoing => colors.outgoing,
|
||||
TextType::Danger | TextType::Sponsor => ext.red_alert_color,
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ use crate::{Language, StyleType};
|
|||
pub enum Message {
|
||||
/// Run tasks to initialize the app
|
||||
StartApp(Option<window::Id>),
|
||||
/// Animate welcome page
|
||||
Welcome,
|
||||
/// 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
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ pub enum Icon {
|
|||
// Rocket,
|
||||
Settings,
|
||||
Sniffnet,
|
||||
Sniffnet1,
|
||||
Sniffnet2,
|
||||
Sniffnet3,
|
||||
Sniffnet4,
|
||||
SortAscending,
|
||||
SortDescending,
|
||||
SortNeutral,
|
||||
|
|
@ -90,6 +94,10 @@ impl Icon {
|
|||
// Icon::Rocket => 'S',
|
||||
Icon::Settings => 'a',
|
||||
Icon::Sniffnet => 'A',
|
||||
Icon::Sniffnet1 => '!',
|
||||
Icon::Sniffnet2 => '"',
|
||||
Icon::Sniffnet3 => '#',
|
||||
Icon::Sniffnet4 => '$',
|
||||
Icon::Star => 'g',
|
||||
Icon::Warning => 'T',
|
||||
Icon::Waves => 'y',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue