Skip to content

Commit 54e47a0

Browse files
authored
Merge pull request #1002 from GyulyVGC/welcome
Add welcome screen
2 parents c13f515 + 8152ed1 commit 54e47a0

8 files changed

Lines changed: 120 additions & 6 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
All Sniffnet releases with the relative changes are documented in this file.
44

5+
## [UNRELEASED]
6+
- Add animated welcome screen ([#1002](https://github.com/GyulyVGC/sniffnet/pull/1002))
7+
58
## [1.4.2] - 2025-11-04
69
- Send remote notifications via webhook ([#991](https://github.com/GyulyVGC/sniffnet/pull/991) — fixes [#841](https://github.com/GyulyVGC/sniffnet/issues/841))
710
- Pause and resume packet captures ([#992](https://github.com/GyulyVGC/sniffnet/pull/992) — fixes [#551](https://github.com/GyulyVGC/sniffnet/issues/551))

resources/fonts/subset/icons.ttf

1016 Bytes
Binary file not shown.

src/gui/pages/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ pub mod settings_notifications_page;
88
pub mod settings_style_page;
99
pub mod thumbnail_page;
1010
pub mod types;
11+
pub mod welcome_page;

src/gui/pages/welcome_page.rs

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
use crate::StyleType;
2+
use crate::gui::styles::text::TextType;
3+
use crate::gui::types::message::Message;
4+
use crate::utils::types::icon::Icon;
5+
use iced::alignment::{Horizontal, Vertical};
6+
use iced::widget::{Column, Container, Space, Text, vertical_space};
7+
use iced::{Alignment, Font, Length};
8+
9+
pub fn welcome_page<'a>(font: Font, x: u8) -> Container<'a, Message, StyleType> {
10+
let icon = match x {
11+
0..=3 | 20.. => Text::new(""),
12+
4 => Icon::Sniffnet1.to_text(),
13+
5 => Icon::Sniffnet2.to_text(),
14+
6 => Icon::Sniffnet3.to_text(),
15+
7 => Icon::Sniffnet4.to_text(),
16+
8..=19 => Icon::Sniffnet.to_text(),
17+
};
18+
19+
let text = Text::new(match x {
20+
0..=3 | 20.. => "",
21+
4 => "S",
22+
5 => "Sn",
23+
6 => "Sni",
24+
7 => "Snif",
25+
8 => "Sniff",
26+
9 => "Sniffn",
27+
10 => "Sniffne",
28+
11..=19 => "Sniffnet",
29+
});
30+
31+
let text_type = match x {
32+
0..=3 | 20.. => TextType::Welcome(0.0),
33+
4 => TextType::Welcome(0.125),
34+
5 => TextType::Welcome(0.25),
35+
6 => TextType::Welcome(0.375),
36+
7 => TextType::Welcome(0.5),
37+
8 => TextType::Welcome(0.625),
38+
9 => TextType::Welcome(0.750),
39+
10 => TextType::Welcome(0.875),
40+
11..=19 => TextType::Welcome(1.0),
41+
};
42+
43+
let body = Column::new()
44+
.align_x(Alignment::Center)
45+
.push(vertical_space())
46+
.push(icon.size(200).line_height(0.9).class(text_type))
47+
.push(text.font(font).size(75).class(text_type))
48+
.push(Space::with_height(Length::FillPortion(2)));
49+
50+
Container::new(body)
51+
.height(Length::Fill)
52+
.width(Length::Fill)
53+
.align_x(Horizontal::Center)
54+
.align_y(Vertical::Center)
55+
}

src/gui/sniffer.rs

Lines changed: 44 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ use crate::gui::pages::settings_style_page::settings_style_page;
3333
use crate::gui::pages::thumbnail_page::thumbnail_page;
3434
use crate::gui::pages::types::running_page::RunningPage;
3535
use crate::gui::pages::types::settings_page::SettingsPage;
36+
use crate::gui::pages::welcome_page::welcome_page;
3637
use crate::gui::styles::types::custom_palette::{CustomPalette, ExtraStyles};
3738
use crate::gui::styles::types::palette::Palette;
3839
use crate::gui::types::conf::Conf;
@@ -77,6 +78,8 @@ pub const ICON_FONT_FAMILY_NAME: &str = "Icons for Sniffnet";
7778
pub struct Sniffer {
7879
/// Parameters that are persistent across runs
7980
pub conf: Conf,
81+
/// Are we during welcome / quit animation? None if not, true if welcome, false if quit
82+
pub welcome: Option<(bool, u8)>,
8083
/// Capture receiver clone (to close the channel after every run), with the current capture id (to ignore pending messages from previous captures)
8184
pub current_capture_rx: (usize, Option<Receiver<BackendTrafficMessage>>),
8285
/// Capture data
@@ -140,6 +143,7 @@ impl Sniffer {
140143
let capture_source = CaptureSource::from_conf(&conf);
141144
Self {
142145
conf,
146+
welcome: Some((true, 0)),
143147
current_capture_rx: (0, None),
144148
info_traffic: InfoTraffic::default(),
145149
addresses_resolved: HashMap::new(),
@@ -173,6 +177,10 @@ impl Sniffer {
173177
fn keyboard_subscription(&self) -> Subscription<Message> {
174178
const NO_MODIFIER: Modifiers = Modifiers::empty();
175179

180+
if self.welcome.is_some() {
181+
return Subscription::none();
182+
}
183+
176184
if self.thumbnail {
177185
iced::event::listen_with(|event, _, _| match event {
178186
Keyboard(Event::KeyPressed {
@@ -231,8 +239,17 @@ impl Sniffer {
231239
}
232240
}
233241

234-
fn time_subscription() -> Subscription<Message> {
235-
iced::time::every(Duration::from_millis(1000)).map(|_| Message::Periodic)
242+
fn time_subscription(&self) -> Subscription<Message> {
243+
if let Some((w, _)) = self.welcome {
244+
let sub = iced::time::every(Duration::from_millis(100));
245+
if w {
246+
sub.map(|_| Message::Welcome)
247+
} else {
248+
sub.map(|_| Message::Quit)
249+
}
250+
} else {
251+
iced::time::every(Duration::from_millis(1000)).map(|_| Message::Periodic)
252+
}
236253
}
237254

238255
fn window_subscription() -> Subscription<Message> {
@@ -430,8 +447,24 @@ impl Sniffer {
430447
}
431448
Message::QuitWrapper => return self.quit_wrapper(),
432449
Message::Quit => {
433-
let _ = self.conf.clone().store();
434-
return window::close(self.id.unwrap_or_else(Id::unique));
450+
if self.welcome.is_none() {
451+
self.welcome = Some((false, 13));
452+
} else if let Some((false, x)) = self.welcome {
453+
if x <= 2 {
454+
let _ = self.conf.clone().store();
455+
return window::close(self.id.unwrap_or_else(Id::unique));
456+
}
457+
self.welcome = Some((false, x.saturating_sub(1)));
458+
}
459+
}
460+
Message::Welcome => {
461+
if let Some((true, x)) = self.welcome {
462+
if x >= 19 {
463+
self.welcome = None;
464+
} else {
465+
self.welcome = Some((true, x + 1));
466+
}
467+
}
435468
}
436469
Message::CopyIp(ip) => {
437470
self.timing_events.copy_ip_now(ip);
@@ -595,6 +628,10 @@ impl Sniffer {
595628
let font = style.get_extension().font;
596629
let font_headers = style.get_extension().font_headers;
597630

631+
if let Some((_, x)) = self.welcome {
632+
return welcome_page(font, x).into();
633+
}
634+
598635
let header = header(self);
599636

600637
let body = if self.thumbnail {
@@ -676,7 +713,7 @@ impl Sniffer {
676713
Subscription::batch([
677714
self.keyboard_subscription(),
678715
self.mouse_subscription(),
679-
Sniffer::time_subscription(),
716+
self.time_subscription(),
680717
Sniffer::window_subscription(),
681718
])
682719
}
@@ -1895,7 +1932,8 @@ mod tests {
18951932
sniffer.update(Message::ChangeRunningPage(RunningPage::Notifications));
18961933
sniffer.update(Message::DataReprSelection(DataRepr::Bits));
18971934

1898-
// quit the app by sending a CloseRequested message
1935+
// force saving configs by quitting the app
1936+
sniffer.welcome = Some((false, 0));
18991937
sniffer.update(Message::Quit);
19001938

19011939
assert!(path.exists());

src/gui/styles/text.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ pub enum TextType {
1818
Subtitle,
1919
Danger,
2020
Sponsor,
21+
Welcome(f32),
2122
}
2223

2324
/// Returns a formatted caption followed by subtitle, new line, tab, and desc
@@ -71,6 +72,12 @@ pub fn highlight(style: &StyleType, element: TextType) -> Color {
7172
a: 1.0,
7273
}
7374
}
75+
TextType::Welcome(mut n) => {
76+
if !(0.0..=1.0).contains(&n) {
77+
n = 1.0;
78+
}
79+
Color { a: n, ..secondary }
80+
}
7481
TextType::Incoming => colors.secondary,
7582
TextType::Outgoing => colors.outgoing,
7683
TextType::Danger | TextType::Sponsor => ext.red_alert_color,

src/gui/types/message.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ use crate::{Language, StyleType};
2121
pub enum Message {
2222
/// Run tasks to initialize the app
2323
StartApp(Option<window::Id>),
24+
/// Animate welcome page
25+
Welcome,
2426
/// Sent by the backend parsing packets; includes the capture id, new data, new hosts batched data, and whether an offline capture has finished
2527
TickRun(usize, InfoTraffic, Vec<HostMessage>, bool),
2628
/// Capture source selected from the picklist

src/utils/types/icon.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ pub enum Icon {
4242
// Rocket,
4343
Settings,
4444
Sniffnet,
45+
Sniffnet1,
46+
Sniffnet2,
47+
Sniffnet3,
48+
Sniffnet4,
4549
SortAscending,
4650
SortDescending,
4751
SortNeutral,
@@ -90,6 +94,10 @@ impl Icon {
9094
// Icon::Rocket => 'S',
9195
Icon::Settings => 'a',
9296
Icon::Sniffnet => 'A',
97+
Icon::Sniffnet1 => '!',
98+
Icon::Sniffnet2 => '"',
99+
Icon::Sniffnet3 => '#',
100+
Icon::Sniffnet4 => '$',
93101
Icon::Star => 'g',
94102
Icon::Warning => 'T',
95103
Icon::Waves => 'y',

0 commit comments

Comments
 (0)