From e20350302df95effe4841dbbfc55758004586eeb Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Wed, 7 Jun 2023 22:52:25 -0400 Subject: [PATCH 01/29] Implement deserializing hex colors to iced::Color. `iced::Color` doesn't implement `serde::Deserialize` nor `serde::Serialize`. I need `Deserialize` so that custom color schemes can be deserialized into the palette type used in Sniffnet. I implemented ser/de to deserialize from a hex string into the float colors used by `iced`. My reasoning is that hexadecimal colors are easier for color scheme artists. Anecdotally, I've also noticed hex colors are the most prevalent for color schemes. Some schemes also provide RGB, but I haven't encountered float colors yet. For example: * [Catppuccin](https://github.com/catppuccin/catppuccin) * [Dracula](https://draculatheme.com/contribute) * [gruvbox](https://github.com/morhetz/gruvbox) * [Nord](https://github.com/nordtheme/nord) * [Tokyo Night](https://github.com/folke/tokyonight.nvim) --- Cargo.lock | 10 ++ Cargo.toml | 1 + src/gui/styles/types/color_remote.rs | 159 +++++++++++++++++++++++++++ src/gui/styles/types/mod.rs | 1 + src/gui/styles/types/palette.rs | 12 ++ src/gui/styles/types/style_type.rs | 18 +++ 6 files changed, 201 insertions(+) create mode 100644 src/gui/styles/types/color_remote.rs diff --git a/Cargo.lock b/Cargo.lock index 964e04a0..5d9e3ad1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3149,6 +3149,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_test" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "100168a8017b89fd4bcbeb8d857d95a8cfcbde829a7147c09cc82d3ab8d8cb41" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3276,6 +3285,7 @@ dependencies = [ "rodio", "rstest", "serde", + "serde_test", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 9652a3f0..ed7cd46c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ dns-lookup = "2.0.2" [dev-dependencies] rstest = "0.17.0" +serde_test = "1.0.163" #═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════ diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs new file mode 100644 index 00000000..a59f33cb --- /dev/null +++ b/src/gui/styles/types/color_remote.rs @@ -0,0 +1,159 @@ +//! Remote type to implement [serde::Deserialize] and [serde::Serialize] for [iced::Color]. +//! Check [serde's documentation](https://serde.rs/remote-derive.html) for details. +//! +//! This implementation deserializes hexadecimal RGB to float RGB. + +use serde::{ + de::{Error as DeErrorTrait, Unexpected}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +// #aabbcc is seven bytes long +const HEX_STR_LEN: usize = 7; + +/// Serde delegate type for [iced::Color]. +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(remote = "iced::Color")] +pub(super) struct ColorDelegate { + pub r: f32, + pub g: f32, + pub b: f32, + pub a: f32, +} + +impl<'de> Deserialize<'de> for ColorDelegate { + fn deserialize(deserializer: D) -> Result + where + D: Deserializer<'de>, + { + // Field should be a hex string i.e. #aabbcc + let hex = String::deserialize(deserializer)?; + + // The string should be seven bytes long (octothorpe + six hex chars). + // Safety: Hexadecimal is ASCII so bytes are okay here. + let hex_len = hex.len(); + if hex_len == HEX_STR_LEN { + let color = hex + .strip_prefix('#') // Remove the octothorpe or fail + .ok_or_else(|| { + DeErrorTrait::invalid_value( + Unexpected::Char(hex.chars().next().unwrap_or_default()), + &"#", + ) + })? + // Iterating over bytes is safe because hex is ASCII. + // If the hex is not ASCII or invalid hex, then the iterator will short circuit and fail on `from_str_radix` + .bytes() + .step_by(2) // Step by every first hex char of the two char sequence + .zip(hex.bytes().skip(2).step_by(2)) // Step by every second hex char + .map(|(first, second)| { + let maybe_hex = [first, second]; + std::str::from_utf8(&maybe_hex) + .map_err(|_| { + DeErrorTrait::invalid_value(Unexpected::Str(&hex), &"valid hexadecimal") + }) + .and_then(|s| { + u8::from_str_radix(s, 16) + .map_err(DeErrorTrait::custom) + .map(|rgb| rgb as f32 / 255.0) + }) + }) + .collect::, _>>()?; + + // Alpha isn't part of the color scheme. The resulting Vec should always have three elements. + Ok(Self { + r: color[0], + g: color[1], + b: color[2], + a: 1.0, + }) + } else { + Err(DeErrorTrait::invalid_length( + hex_len, + &&*format!("{HEX_STR_LEN}"), + )) + } + } +} + +impl Serialize for ColorDelegate { + // Serialize Color as a hex string. + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + // ColorDelegate to iced::Color + let Self { r, g, b, a } = *self; + let color = iced::Color { r, g, b, a }; + + // iced::Color to [u8; 4] + let color = color.into_rgba8(); + + // [u8; 3] to hex string (alpha isn't serialized because it should be 0xff anyway) + let hex_color: String = format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]); + + // Serialize the hex string + serializer.serialize_str(&hex_color) + } +} + +#[cfg(test)] +mod tests { + use super::ColorDelegate; + use serde_test::{assert_de_tokens_error, assert_tokens, Token}; + + // https://github.com/catppuccin/catppuccin + const CATPPUCCIN_PINK_HEX: &str = "#f5c2e7"; + const CATPPUCCIN_PINK: ColorDelegate = ColorDelegate { + r: 245.0 / 255.0, + g: 194.0 / 255.0, + b: 231.0 / 255.0, + a: 1.0, + }; + + // Invalid hex colors + const CATPPUCCIN_PINK_NO_OCTO: &str = "%f5c2e7"; + const CATPPUCCIN_PINK_TRUNCATED: &str = "#c2e7"; + const CATPPUCCIN_PINK_TOO_LONG: &str = "#f5c2e7f5c2e7f5"; + const INVALID_COLOR: &str = "#ca🐈"; + + // Test if deserializing and serializing ColorDelegate works. + #[test] + fn test_working_color_round_trip() { + assert_tokens(&CATPPUCCIN_PINK, &[Token::Str(CATPPUCCIN_PINK_HEX)]); + } + + // Missing octothorpe should fail. + #[test] + fn test_no_octothrope_color_rt() { + assert_de_tokens_error::( + &[Token::Str(CATPPUCCIN_PINK_NO_OCTO)], + "invalid value: character `%`, expected #", + ); + } + + // A hex color that is missing components should panic. + #[test] + fn test_len_too_small_color_de() { + assert_de_tokens_error::( + &[Token::Str(CATPPUCCIN_PINK_TRUNCATED)], + "invalid length 5, expected 7", + ); + } + + #[test] + fn test_len_too_large_color_de() { + assert_de_tokens_error::( + &[Token::Str(CATPPUCCIN_PINK_TOO_LONG)], + "invalid length 15, expected 7", + ); + } + + #[test] + fn test_invalid_hex_color_de() { + assert_de_tokens_error::( + &[Token::Str(INVALID_COLOR)], + "invalid value: string \"#ca🐈\", expected valid hexadecimal", + ); + } +} diff --git a/src/gui/styles/types/mod.rs b/src/gui/styles/types/mod.rs index 629f43df..00bbf38b 100644 --- a/src/gui/styles/types/mod.rs +++ b/src/gui/styles/types/mod.rs @@ -1,3 +1,4 @@ +pub(super) mod color_remote; pub mod element_type; pub mod palette; pub mod style_tuple; diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 4679ffd2..43a6a277 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -2,11 +2,13 @@ use iced::Color; use plotters::style::RGBColor; +use serde::{Deserialize, Serialize}; use crate::gui::styles::style_constants::{ DAY_STYLE, DEEP_SEA_STYLE, MON_AMOUR_STYLE, NIGHT_STYLE, }; use crate::StyleType; +use super::color_remote::ColorDelegate; /// Set of colors to apply to GUI /// @@ -17,24 +19,34 @@ use crate::StyleType; /// - `incoming` and `outgoing` should be complementary colors if possible /// - `text_headers` should be black or white and must have a strong contrast with `secondary` /// - `text_body` should be black or white and must have a strong contrast with `primary` +#[derive(Deserialize, Serialize)] pub struct Palette { /// Main color of the GUI (background, hovered buttons, active tab) + #[serde(with = "ColorDelegate")] pub primary: Color, /// Secondary color of the GUI (header, footer, buttons' borders, radio selection) + #[serde(with = "ColorDelegate")] pub secondary: Color, /// Color of active buttons (when not hovered) and inactive tabs + #[serde(with = "ColorDelegate")] pub buttons: Color, /// Color of incoming connections + #[serde(with = "ColorDelegate")] pub incoming: Color, /// Color of outgoing connections + #[serde(with = "ColorDelegate")] pub outgoing: Color, /// Color of header and footer text + #[serde(with = "ColorDelegate")] pub text_headers: Color, /// Color of body and buttons text + #[serde(with = "ColorDelegate")] pub text_body: Color, /// Color of round container borders and scrollbar borders + #[serde(with = "ColorDelegate")] pub round_borders: Color, /// Color of round containers + #[serde(with = "ColorDelegate")] pub round_containers: Color, } diff --git a/src/gui/styles/types/style_type.rs b/src/gui/styles/types/style_type.rs index 5d46a48b..4bdb2aa7 100644 --- a/src/gui/styles/types/style_type.rs +++ b/src/gui/styles/types/style_type.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use super::palette::Palette; /// Used to specify the kind of style of the application #[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash, PartialEq)] @@ -14,3 +15,20 @@ impl Default for StyleType { Self::Night } } + +/// Custom sniffnet color scheme. +// #[derive(Clone, Deserialize, Debug, Hash)] +pub struct CustomStyle { + /// Display name of the color scheme. + /// This is the user facing color scheme name that may be displayed in the UI. + /// Ex. Catppuccin Mocha + pub name: String, + /// Internal or path name. + /// Ex. catppuccin_mocha.toml + pub path: String, + /// Short description of the color scheme + pub description: String, + /// Color scheme's sniffnet palette. + /// Should be an implementation of the scheme that is tuned to sniffnet. + pub palette: Palette +} From e7fa2f8b8fcffccef9e028964b3c8ec2083fabe6 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Fri, 16 Jun 2023 19:17:08 -0400 Subject: [PATCH 02/29] Clean up ser/de implementations for `Color`. Previously, I implemented a remote type to serialize and deserialize `iced::Color`. That implementation caused some problems when writing the unit tests because `serde_test` expected the `iced::Color` struct. I didn't want to overhaul the tests from their concise and more direct implementations - especially considering I don't really understand the problem. Anyway, using `deserialize_with` and `serialize_with` is cleaner than remote derive so this is overall a win. I implemented `PartialEq` for the custom style's palette's to account for floating point's imprecision. I also fixed an incorrectly copied number that caused the unit tests to fail. With that, deserializing custom styles from TOML seems to work and all unit tests pass. --- src/gui/styles/types/color_remote.rs | 251 ++++++++++++++++----------- src/gui/styles/types/custom_style.rs | 64 ++++++- src/gui/styles/types/palette.rs | 22 +-- 3 files changed, 221 insertions(+), 116 deletions(-) diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index 7233ed63..5116668e 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -1,11 +1,14 @@ -//! Remote type to implement [serde::Deserialize] and [serde::Serialize] for [iced::Color]. -//! Check [serde's documentation](https://serde.rs/remote-derive.html) for details. +//! Remote implemention of [serde::Deserialize] and [serde::Serialize] for [iced::Color]. //! -//! This implementation deserializes hexadecimal RGB to float RGB. +//! This implementation deserializes hexadecimal RGB(A) as string to float RGB(A) and back. +//! NOTE: The alpha channel is optional and defaults to #ff or 1.0. +//! `#ffffffff` deserializes to `1.0`, `1.0`, `1.0`, `1.0`. +//! `1.0`, `1.0`, `1.0`, `1.0` serializes to #ffffffff +use iced::Color; use serde::{ de::{Error as DeErrorTrait, Unexpected}, - Deserialize, Deserializer, Serialize, Serializer, + Deserialize, Deserializer, Serializer, }; // #aabbcc is seven bytes long @@ -14,122 +17,161 @@ const HEX_STR_BASE_LEN: usize = 7; const HEX_STR_ALPHA_LEN: usize = 9; /// Serde delegate type for [iced::Color]. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(remote = "iced::Color")] -pub(super) struct ColorDelegate { - pub r: f32, - pub g: f32, - pub b: f32, - pub a: f32, -} - -impl<'de> Deserialize<'de> for ColorDelegate { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - // Field should be a hex string i.e. #aabbcc - let hex = String::deserialize(deserializer)?; - - // The string should be seven bytes long (octothorpe + six hex chars). - // Safety: Hexadecimal is ASCII so bytes are okay here. - let hex_len = hex.len(); - if hex_len == HEX_STR_BASE_LEN || hex_len == HEX_STR_ALPHA_LEN { - let color = hex - .strip_prefix('#') // Remove the octothorpe or fail - .ok_or_else(|| { - DeErrorTrait::invalid_value( - Unexpected::Char(hex.chars().next().unwrap_or_default()), - &"#", - ) - })? - // Iterating over bytes is safe because hex is ASCII. - // If the hex is not ASCII or invalid hex, then the iterator will short circuit and fail on `from_str_radix` - .bytes() - .step_by(2) // Step by every first hex char of the two char sequence - .zip(hex.bytes().skip(2).step_by(2)) // Step by every second hex char - .map(|(first, second)| { - // Parse hex strings - let maybe_hex = [first, second]; - std::str::from_utf8(&maybe_hex) - .map_err(|_| { - DeErrorTrait::invalid_value(Unexpected::Str(&hex), &"valid hexadecimal") - }) - .and_then(|s| { - u8::from_str_radix(s, 16) - .map_err(DeErrorTrait::custom) - .map(|rgb| rgb as f32 / 255.0) - }) - }) - .collect::, _>>()?; - - // Alpha isn't always part of the color scheme. The resulting Vec should always have at least three elements. - Ok(Self { - r: color[0], - g: color[1], - b: color[2], - a: *color.get(3).unwrap_or(&1.0), +// #[derive(Debug, PartialEq, Serialize, Deserialize)] +// #[serde(remote = "iced::Color")] +// pub(super) struct ColorDelegate { +// pub r: f32, +// pub g: f32, +// pub b: f32, +// pub a: f32, +// } + +pub(super) fn deserialize_color<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + // Field should be a hex string i.e. #aabbcc + let hex = String::deserialize(deserializer)?; + + // The string should be seven bytes long (octothorpe + six hex chars). + // Safety: Hexadecimal is ASCII so bytes are okay here. + let hex_len = hex.len(); + if hex_len == HEX_STR_BASE_LEN || hex_len == HEX_STR_ALPHA_LEN { + let color = hex + .strip_prefix('#') // Remove the octothorpe or fail + .ok_or_else(|| { + DeErrorTrait::invalid_value( + Unexpected::Char(hex.chars().next().unwrap_or_default()), + &"#", + ) + })? + // Iterating over bytes is safe because hex is ASCII. + // If the hex is not ASCII or invalid hex, then the iterator will short circuit and fail on `from_str_radix` + // TODO: This can be cleaned up when `iter_array_chunks` is stablized (https://github.com/rust-lang/rust/issues/100450) + .bytes() + .step_by(2) // Step by every first hex char of the two char sequence + .zip(hex.bytes().skip(2).step_by(2)) // Step by every second hex char + .map(|(first, second)| { + // Parse hex strings + let maybe_hex = [first, second]; + std::str::from_utf8(&maybe_hex) + .map_err(|_| { + DeErrorTrait::invalid_value(Unexpected::Str(&hex), &"valid hexadecimal") + }) + .and_then(|s| { + u8::from_str_radix(s, 16) + .map_err(DeErrorTrait::custom) + .map(|rgb| rgb as f32 / 255.0) + }) }) - } else { - Err(DeErrorTrait::invalid_length( - hex_len, - &&*format!("{HEX_STR_BASE_LEN} or {HEX_STR_ALPHA_LEN}"), - )) - } + .collect::, _>>()?; + + // Alpha isn't always part of the color scheme. The resulting Vec should always have at least three elements. + // Accessing the first three elements without [slice::get] is okay because I checked the length of the hex string earlier. + Ok(Color { + r: color[0], + g: color[1], + b: color[2], + a: *color.get(3).unwrap_or(&1.0), + }) + } else { + Err(DeErrorTrait::invalid_length( + hex_len, + &&*format!("{HEX_STR_BASE_LEN} or {HEX_STR_ALPHA_LEN}"), + )) } } -impl Serialize for ColorDelegate { - // Serialize Color as a hex string. - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - // ColorDelegate to iced::Color - let Self { r, g, b, a } = *self; - let color = iced::Color { r, g, b, a }; - - // iced::Color to [u8; 4] - let color = color.into_rgba8(); +/// Serialize [iced::Color] as a hex string. +#[inline] +pub(super) fn serialize_color(color: &Color, serializer: S) -> Result +where + S: Serializer, +{ + // iced::Color to [u8; 4] + let color = color.into_rgba8(); + + // [u8; 4] to hex string, precluding the alpha if it's 0xff. + let hex_color = if color[3] != 255 { + format!( + "#{:02x}{:02x}{:02x}{:02x}", + color[0], color[1], color[2], color[3] + ) + } else { + format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]) + }; - // [u8; 3] to hex string (alpha isn't serialized because it should be 0xff anyway) - let hex_color: String = format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]); + // Serialize the hex string + serializer.serialize_str(&hex_color) +} - // Serialize the hex string - serializer.serialize_str(&hex_color) +// Round and truncate [Color] to facilitate comparisons. +#[cfg(test)] +pub(super) fn color_round(color: Color) -> Color { + let Color { r, g, b, a } = color; + Color { + r: (r * 1000.0).trunc(), + g: (g * 1000.0).trunc(), + b: (b * 1000.0).trunc(), + a: (a * 1000.0).trunc(), } } +// Lower precision float equality for unit tests. +#[cfg(test)] +pub(super) fn color_partialeq(color: Color, other: Color) -> bool { + let color = color_round(color); + let other = color_round(other); + color == other +} + #[cfg(test)] mod tests { - use super::ColorDelegate; + use super::{color_partialeq, deserialize_color, serialize_color}; use iced::Color; use serde::{Deserialize, Serialize}; use serde_test::{assert_de_tokens_error, assert_tokens, Token}; // https://github.com/catppuccin/catppuccin const CATPPUCCIN_PINK_HEX: &str = "#f5c2e7"; - const CATPPUCCIN_PINK: ColorDelegate = ColorDelegate { + const CATPPUCCIN_PINK: Color = Color { r: 245.0 / 255.0, g: 194.0 / 255.0, b: 231.0 / 255.0, a: 1.0, }; - #[derive(Debug, PartialEq, Serialize, Deserialize)] + const CATPPUCCIN_PINK_HEX_ALPHA: &str = "#f5c2e780"; + const CATPPUCCIN_PINK_ALPHA: Color = Color { + r: 245.0 / 255.0, + g: 194.0 / 255.0, + b: 231.0 / 255.0, + a: 128.0 / 255.0, + }; + + #[derive(Debug, Deserialize, Serialize)] #[serde(transparent)] struct DelegateTest { - #[serde(flatten, with = "ColorDelegate")] + #[serde( + flatten, + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] color: Color, } - const ICED_CATPPUCCIN_PINK: DelegateTest = DelegateTest { - color: Color { - r: 245.0 / 255.0, - g: 194.0 / 255.0, - b: 231.0 / 255.0, - a: 1.0, - }, + impl PartialEq for DelegateTest { + fn eq(&self, other: &Self) -> bool { + color_partialeq(self.color, other.color) + } + } + + const CATPPUCCIN_PINK_DELEGATE: DelegateTest = DelegateTest { + color: CATPPUCCIN_PINK, + }; + + const CATPPUCCIN_PINK_ALPHA_DELEGATE: DelegateTest = DelegateTest { + color: CATPPUCCIN_PINK_ALPHA, }; // Invalid hex colors @@ -138,22 +180,28 @@ mod tests { const CATPPUCCIN_PINK_TOO_LONG: &str = "#f5c2e7f5c2e7f5"; const INVALID_COLOR: &str = "#ca🐈"; - // Test if deserializing and serializing ColorDelegate works. + // Test if deserializing and serializing a color works. #[test] fn test_working_color_round_trip() { - assert_tokens(&CATPPUCCIN_PINK, &[Token::Str(CATPPUCCIN_PINK_HEX)]); + assert_tokens( + &CATPPUCCIN_PINK_DELEGATE, + &[Token::Str(CATPPUCCIN_PINK_HEX)], + ); } - // Test iced::Color using ColorDelegate as a delegate + // Test if deserializing and serializing a color with an alpha channel works. #[test] - fn test_working_iced_color_round_trip() { - serde_test::assert_de_tokens(&ICED_CATPPUCCIN_PINK, &[Token::Str(CATPPUCCIN_PINK_HEX)]); + fn test_working_color_with_alpha_round_trip() { + assert_tokens( + &CATPPUCCIN_PINK_ALPHA_DELEGATE, + &[Token::Str(CATPPUCCIN_PINK_HEX_ALPHA)], + ); } // Missing octothorpe should fail. #[test] fn test_no_octothrope_color_rt() { - assert_de_tokens_error::( + assert_de_tokens_error::( &[Token::Str(CATPPUCCIN_PINK_NO_OCTO)], "invalid value: character `%`, expected #", ); @@ -162,7 +210,7 @@ mod tests { // A hex color that is missing components should panic. #[test] fn test_len_too_small_color_de() { - assert_de_tokens_error::( + assert_de_tokens_error::( &[Token::Str(CATPPUCCIN_PINK_TRUNCATED)], "invalid length 5, expected 7 or 9", ); @@ -170,15 +218,16 @@ mod tests { #[test] fn test_len_too_large_color_de() { - assert_de_tokens_error::( + assert_de_tokens_error::( &[Token::Str(CATPPUCCIN_PINK_TOO_LONG)], "invalid length 15, expected 7 or 9", ); } + // Invalid hexadecimal should panic #[test] fn test_invalid_hex_color_de() { - assert_de_tokens_error::( + assert_de_tokens_error::( &[Token::Str(INVALID_COLOR)], "invalid value: string \"#ca🐈\", expected valid hexadecimal", ); diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 09a2cf27..8f8e8092 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -11,8 +11,12 @@ use std::{ use super::palette::{Palette, PaletteExtension}; +#[cfg(test)] +use super::color_remote::color_partialeq; + /// Custom color scheme data including the palette, name, and location of the toml. -#[derive(Debug, PartialEq, Deserialize)] +#[cfg_attr(test, derive(PartialEq))] +#[derive(Debug, Deserialize)] pub struct CustomStyle { /// Display name of the color scheme. /// This is the user facing color scheme name that may be displayed in the UI. @@ -36,8 +40,8 @@ pub struct CustomStyle { pub palette: CustomPalette, } -/// Palette for [CustomStyle]. -#[derive(Deserialize, Debug, PartialEq)] +/// Base [Palette] and extension colors for [CustomStyle]. +#[derive(Debug, Deserialize)] pub struct CustomPalette { /// Base colors as used for the default sniffnet themes. #[serde(flatten)] @@ -47,6 +51,58 @@ pub struct CustomPalette { pub extension: PaletteExtension, } +#[cfg(test)] +impl PartialEq for CustomPalette { + fn eq(&self, other: &Self) -> bool { + let Palette { + primary, + secondary, + buttons, + incoming, + outgoing, + text_headers, + text_body, + round_borders, + round_containers, + } = self.base; + + let PaletteExtension { + starred, + badge_alpha, + } = self.extension; + + // Other + let Palette { + primary: primary_other, + secondary: secondary_other, + buttons: buttons_other, + incoming: incoming_other, + outgoing: outgoing_other, + text_headers: text_headers_other, + text_body: text_body_other, + round_borders: round_borders_other, + round_containers: round_containers_other, + } = other.base; + + let PaletteExtension { + starred: starred_other, + badge_alpha: badge_alpha_other, + } = other.extension; + + color_partialeq(primary, primary_other) + && color_partialeq(secondary, secondary_other) + && color_partialeq(buttons, buttons_other) + && color_partialeq(incoming, incoming_other) + && color_partialeq(outgoing, outgoing_other) + && color_partialeq(text_headers, text_headers_other) + && color_partialeq(text_body, text_body_other) + && color_partialeq(round_borders, round_borders_other) + && color_partialeq(round_containers, round_containers_other) + && color_partialeq(starred, starred_other) + && badge_alpha == badge_alpha_other + } +} + /// Deserialize [CustomStyle] by first deserializing a file path which in turn contains the style as TOML. pub(super) fn deserialize_from_path<'de, D>(deserializer: D) -> Result where @@ -162,7 +218,7 @@ mod tests { round_borders: Color { r: 116.0 / 255.0, g: 199.0 / 255.0, - b: 250.0 / 255.0, + b: 236.0 / 255.0, a: 1.0, }, round_containers: Color { diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 06c449ab..2aa9ffdf 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -4,7 +4,7 @@ use iced::Color; use plotters::style::RGBColor; use serde::{Deserialize, Serialize}; -use super::color_remote::ColorDelegate; +use super::color_remote::{deserialize_color, serialize_color}; use crate::gui::styles::style_constants::{ DAY_STYLE, DEEP_SEA_STYLE, MON_AMOUR_STYLE, NIGHT_STYLE, }; @@ -22,31 +22,31 @@ use crate::StyleType; #[derive(Debug, PartialEq, Deserialize, Serialize)] pub struct Palette { /// Main color of the GUI (background, hovered buttons, active tab) - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub primary: Color, /// Secondary color of the GUI (header, footer, buttons' borders, radio selection) - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub secondary: Color, /// Color of active buttons (when not hovered) and inactive tabs - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub buttons: Color, /// Color of incoming connections - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub incoming: Color, /// Color of outgoing connections - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub outgoing: Color, /// Color of header and footer text - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub text_headers: Color, /// Color of body and buttons text - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub text_body: Color, /// Color of round container borders and scrollbar borders - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub round_borders: Color, /// Color of round containers - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub round_containers: Color, } @@ -100,7 +100,7 @@ impl Default for Palette { #[derive(Debug, PartialEq, Deserialize)] pub struct PaletteExtension { /// Color of favorites star - #[serde(with = "ColorDelegate")] + #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] pub starred: Color, /// Badge alpha channel pub badge_alpha: f32, From 263205a87e30d0917c67b2a6e792d5ab07ea3b41 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Sat, 17 Jun 2023 22:16:36 -0400 Subject: [PATCH 03/29] Support multilingual custom theme descriptions. - Add support for descriptions in other languages. - Use the latest `toml` crate because `confy`'s version had a bug that my code is hitting. Deserializing the `Language` enum in a TOML table failed with an error that claimed that the enum isn't a key. Upgrading the `toml` crate solved that problem. - Clean up TOML theme spec. --- Cargo.lock | 64 +++++++++++++++++++++++--- Cargo.toml | 2 +- resources/themes/catppuccin_mocha.toml | 7 ++- src/gui/styles/types/color_remote.rs | 12 +++++ src/gui/styles/types/custom_style.rs | 37 ++++++++++----- src/gui/styles/types/palette.rs | 2 +- 6 files changed, 103 insertions(+), 21 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4f24b062..c6bbfc96 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -438,7 +438,7 @@ dependencies = [ "directories", "serde", "thiserror", - "toml", + "toml 0.5.11", ] [[package]] @@ -914,7 +914,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59a98bbaacea1c0eb6a0876280051b892eb73594fd90cf3b20e9c817029c57d2" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] @@ -2551,7 +2551,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" dependencies = [ "once_cell", - "toml_edit", + "toml_edit 0.18.1", ] [[package]] @@ -3046,6 +3046,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +dependencies = [ + "serde", +] + [[package]] name = "serde_test" version = "1.0.163" @@ -3183,7 +3192,7 @@ dependencies = [ "rstest", "serde", "serde_test", - "toml", + "toml 0.7.4", "winres", ] @@ -3507,12 +3516,33 @@ dependencies = [ "serde", ] +[[package]] +name = "toml" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime 0.6.2", + "toml_edit 0.19.10", +] + [[package]] name = "toml_datetime" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" +[[package]] +name = "toml_datetime" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +dependencies = [ + "serde", +] + [[package]] name = "toml_edit" version = "0.18.1" @@ -3521,7 +3551,20 @@ checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" dependencies = [ "indexmap", "nom8", - "toml_datetime", + "toml_datetime 0.5.1", +] + +[[package]] +name = "toml_edit" +version = "0.19.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime 0.6.2", + "winnow", ] [[package]] @@ -4315,6 +4358,15 @@ dependencies = [ "x11-dl", ] +[[package]] +name = "winnow" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -4330,7 +4382,7 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b68db261ef59e9e52806f688020631e987592bd83619edccda9c47d42cde4f6c" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 16af00af..f757b727 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,7 +49,7 @@ serde = { version = "1.0.163", default_features = false, features = ["derive"] } rodio = { version = "0.17.1", default_features = false, features = ["mp3"] } reqwest = { version = "0.11.18", default-features = false, features = ["json", "blocking", "rustls-tls"] } dns-lookup = "2.0.2" -toml = "0.5" +toml = "0.7.4" #─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index 5ab30637..e424b18d 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -1,6 +1,11 @@ name = "Catppuccin (Mocha)" -description = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin" +[description] +EN = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin" +# Contributed by Bartosz +PL = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin" + +[palette] primary = "#1e1e2e" # Base secondary = "#89b4fa" # Blue buttons = "#89dceb" # Sky diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index 5116668e..45164000 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -232,4 +232,16 @@ mod tests { "invalid value: string \"#ca🐈\", expected valid hexadecimal", ); } + + // Test that colors are rounded correctly + #[test] + fn test_color_rounding() { + + } + + // Test imprecise, fake PartialEq for [iced::Color] + #[test] + fn test_color_partialeq() { + + } } diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 8f8e8092..81a417b8 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -3,20 +3,22 @@ //! ```toml //! ``` -use serde::{de::Error as DeErrorTrait, Deserialize, Deserializer, Serializer}; +use serde::{de::Error as DeErrorTrait, Deserialize, Deserializer, Serialize, Serializer}; use std::{ + collections::HashMap, fs::File, io::{BufReader, Read}, }; use super::palette::{Palette, PaletteExtension}; +use crate::Language; #[cfg(test)] use super::color_remote::color_partialeq; /// Custom color scheme data including the palette, name, and location of the toml. #[cfg_attr(test, derive(PartialEq))] -#[derive(Debug, Deserialize)] +#[derive(Debug, Deserialize, Serialize)] pub struct CustomStyle { /// Display name of the color scheme. /// This is the user facing color scheme name that may be displayed in the UI. @@ -29,19 +31,18 @@ pub struct CustomStyle { #[serde(skip)] pub path: String, /// Short description of the color scheme - pub description: String, + pub description: HashMap, /// Color scheme's Sniffnet palette. /// Should be an implementation of the scheme that is tuned to Sniffnet. - // NOTE: This is flattened for ergonomics. With flatten, both [Palette] and [PaletteExtension] can be - // defined in the TOML as a single entity rather than two separate listings. This is intentional because - // the separation between palette and its extension is an implementation detail that shouldn't be exposed - // to custom theme designers. - #[serde(flatten)] pub palette: CustomPalette, } /// Base [Palette] and extension colors for [CustomStyle]. -#[derive(Debug, Deserialize)] +// NOTE: This is flattened for ergonomics. With flatten, both [Palette] and [PaletteExtension] can be +// defined in the TOML as a single entity rather than two separate tables. This is intentional because +// the separation between palette and its extension is an implementation detail that shouldn't be exposed +// to custom theme designers. +#[derive(Debug, Deserialize, Serialize)] pub struct CustomPalette { /// Base colors as used for the default sniffnet themes. #[serde(flatten)] @@ -103,7 +104,9 @@ impl PartialEq for CustomPalette { } } -/// Deserialize [CustomStyle] by first deserializing a file path which in turn contains the style as TOML. +/// Deserialize [CustomStyle] from a file path. +/// +/// This is implemented by first deserializing a file path which in turn contains the style as TOML. pub(super) fn deserialize_from_path<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -125,6 +128,9 @@ where } /// Serialize [CustomStyle]'s path. +/// +/// Themes aren't serialized because they're already located somewhere else (the TOML file from which it was loaded). +/// However, the theme's path must be serialized so that Sniffnet can reload it after the program is restarted. #[inline] pub(super) fn serialize_to_path(style: &CustomStyle, serializer: S) -> Result where @@ -139,9 +145,11 @@ mod tests { deserialize_from_path, serialize_to_path, CustomPalette, CustomStyle, Palette, PaletteExtension, }; + use crate::translations::types::language::Language; use iced::Color; use serde::{Deserialize, Serialize}; use serde_test::{assert_tokens, Token}; + use std::collections::HashMap; // Convenience struct for testing #[derive(Debug, PartialEq, Deserialize, Serialize)] @@ -164,13 +172,18 @@ mod tests { ) } - const STYLE_DESC: &str = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin"; + const STYLE_DESC_ENG: &str = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin"; + // Polish translation by Bartosz. + const STYLE_DESC_PL: &str = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin"; fn catppuccin_style() -> StyleForTests { StyleForTests(CustomStyle { name: "Catppuccin (Mocha)".to_owned(), path: style_path(), - description: STYLE_DESC.to_owned(), + description: HashMap::from([ + (Language::EN, STYLE_DESC_ENG.to_owned()), + (Language::PL, STYLE_DESC_PL.to_owned()), + ]), palette: CustomPalette { base: Palette { primary: Color { diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 2aa9ffdf..aecb94bf 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -97,7 +97,7 @@ impl Default for Palette { /// Extension colors for custom themes. // NOTE: The purpose of this type is primarily to avoid modifying the existing [Palette]. -#[derive(Debug, PartialEq, Deserialize)] +#[derive(Debug, PartialEq, Deserialize, Serialize)] pub struct PaletteExtension { /// Color of favorites star #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] From 64efb61c803385d6f9c3f29ccb42949c18004372 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Sun, 18 Jun 2023 23:04:38 -0400 Subject: [PATCH 04/29] Implement Hash for custom style types. Primarily to keep parity with the types that derived Hash before these patches. --- resources/themes/catppuccin_mocha.toml | 2 + src/gui/styles/types/color_remote.rs | 35 +++++++--- src/gui/styles/types/custom_style.rs | 29 ++++---- src/gui/styles/types/palette.rs | 94 ++++++++++++++++++++++---- src/gui/styles/types/style_type.rs | 3 + src/translations/types/language.rs | 2 +- 6 files changed, 130 insertions(+), 35 deletions(-) diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index e424b18d..e3885a5a 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -2,6 +2,8 @@ name = "Catppuccin (Mocha)" [description] EN = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin" +# Contributed by Emilia +# HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" # Contributed by Bartosz PL = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin" diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index 45164000..54ba8f2b 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -10,6 +10,7 @@ use serde::{ de::{Error as DeErrorTrait, Unexpected}, Deserialize, Deserializer, Serializer, }; +use std::hash::{Hash, Hasher}; // #aabbcc is seven bytes long const HEX_STR_BASE_LEN: usize = 7; @@ -82,6 +83,14 @@ where } } +/// Hash delegate for [iced::Color] that hashes RGBA in lieu of floats. +#[inline] +pub(super) fn color_hash(color: Color, state: &mut H) { + // Hash isn't implemented for floats, so I hash the color as RGBA instead. + let color = color.into_rgba8(); + color.hash(state); +} + /// Serialize [iced::Color] as a hex string. #[inline] pub(super) fn serialize_color(color: &Color, serializer: S) -> Result @@ -106,7 +115,6 @@ where } // Round and truncate [Color] to facilitate comparisons. -#[cfg(test)] pub(super) fn color_round(color: Color) -> Color { let Color { r, g, b, a } = color; Color { @@ -117,8 +125,7 @@ pub(super) fn color_round(color: Color) -> Color { } } -// Lower precision float equality for unit tests. -#[cfg(test)] +// Lower precision float equality for unit tests and cases where we need Color comparisons. pub(super) fn color_partialeq(color: Color, other: Color) -> bool { let color = color_round(color); let other = color_round(other); @@ -127,7 +134,7 @@ pub(super) fn color_partialeq(color: Color, other: Color) -> bool { #[cfg(test)] mod tests { - use super::{color_partialeq, deserialize_color, serialize_color}; + use super::{color_partialeq, color_round, deserialize_color, serialize_color}; use iced::Color; use serde::{Deserialize, Serialize}; use serde_test::{assert_de_tokens_error, assert_tokens, Token}; @@ -236,12 +243,22 @@ mod tests { // Test that colors are rounded correctly #[test] fn test_color_rounding() { + let color = Color { + r: 1.0 / 3.0, + g: 2.0 / 3.0, + b: 3.0 / 3.0, + #[allow(clippy::excessive_precision)] + a: 1.618033988749, + }; - } - - // Test imprecise, fake PartialEq for [iced::Color] - #[test] - fn test_color_partialeq() { + let color_rounded = color_round(color); + let color_expected = Color { + r: 333.0, + g: 666.0, + b: 1000.0, + a: 1618.0, + }; + assert_eq!(color_expected, color_rounded); } } diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 81a417b8..2cb8e92c 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -5,20 +5,19 @@ use serde::{de::Error as DeErrorTrait, Deserialize, Deserializer, Serialize, Serializer}; use std::{ - collections::HashMap, + collections::BTreeMap, fs::File, io::{BufReader, Read}, }; -use super::palette::{Palette, PaletteExtension}; +use super::{ + color_remote::color_partialeq, + palette::{Palette, PaletteExtension}, +}; use crate::Language; -#[cfg(test)] -use super::color_remote::color_partialeq; - /// Custom color scheme data including the palette, name, and location of the toml. -#[cfg_attr(test, derive(PartialEq))] -#[derive(Debug, Deserialize, Serialize)] +#[derive(Debug, PartialEq, Hash, Clone, Deserialize, Serialize)] pub struct CustomStyle { /// Display name of the color scheme. /// This is the user facing color scheme name that may be displayed in the UI. @@ -31,7 +30,7 @@ pub struct CustomStyle { #[serde(skip)] pub path: String, /// Short description of the color scheme - pub description: HashMap, + pub description: BTreeMap, /// Color scheme's Sniffnet palette. /// Should be an implementation of the scheme that is tuned to Sniffnet. pub palette: CustomPalette, @@ -42,7 +41,11 @@ pub struct CustomStyle { // defined in the TOML as a single entity rather than two separate tables. This is intentional because // the separation between palette and its extension is an implementation detail that shouldn't be exposed // to custom theme designers. -#[derive(Debug, Deserialize, Serialize)] +// +// Clippy complains about deriving [Hash] with a manually written [PartialEq]. We manually implemented +// Hash for [Palette] and [PaletteExtension], so deriving Hash is convenient and the error is spurious. +#[allow(clippy::derived_hash_with_manual_eq)] +#[derive(Debug, Hash, Clone, Deserialize, Serialize)] pub struct CustomPalette { /// Base colors as used for the default sniffnet themes. #[serde(flatten)] @@ -52,7 +55,6 @@ pub struct CustomPalette { pub extension: PaletteExtension, } -#[cfg(test)] impl PartialEq for CustomPalette { fn eq(&self, other: &Self) -> bool { let Palette { @@ -149,7 +151,7 @@ mod tests { use iced::Color; use serde::{Deserialize, Serialize}; use serde_test::{assert_tokens, Token}; - use std::collections::HashMap; + use std::collections::BTreeMap; // Convenience struct for testing #[derive(Debug, PartialEq, Deserialize, Serialize)] @@ -173,6 +175,8 @@ mod tests { } const STYLE_DESC_ENG: &str = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin"; + // Hungarian translation by Emi. + const STYLE_DESC_HU: &str = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin"; // Polish translation by Bartosz. const STYLE_DESC_PL: &str = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin"; @@ -180,8 +184,9 @@ mod tests { StyleForTests(CustomStyle { name: "Catppuccin (Mocha)".to_owned(), path: style_path(), - description: HashMap::from([ + description: BTreeMap::from([ (Language::EN, STYLE_DESC_ENG.to_owned()), + // (Language::HU, STYLE_DESC_HU.to_owned()), (Language::PL, STYLE_DESC_PL.to_owned()), ]), palette: CustomPalette { diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index aecb94bf..0fd076a9 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -3,8 +3,9 @@ use iced::Color; use plotters::style::RGBColor; use serde::{Deserialize, Serialize}; +use std::hash::{Hash, Hasher}; -use super::color_remote::{deserialize_color, serialize_color}; +use super::color_remote::{color_hash, deserialize_color, serialize_color}; use crate::gui::styles::style_constants::{ DAY_STYLE, DEEP_SEA_STYLE, MON_AMOUR_STYLE, NIGHT_STYLE, }; @@ -19,34 +20,61 @@ use crate::StyleType; /// - `incoming` and `outgoing` should be complementary colors if possible /// - `text_headers` should be black or white and must have a strong contrast with `secondary` /// - `text_body` should be black or white and must have a strong contrast with `primary` -#[derive(Debug, PartialEq, Deserialize, Serialize)] +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] pub struct Palette { /// Main color of the GUI (background, hovered buttons, active tab) - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub primary: Color, /// Secondary color of the GUI (header, footer, buttons' borders, radio selection) - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub secondary: Color, /// Color of active buttons (when not hovered) and inactive tabs - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub buttons: Color, /// Color of incoming connections - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub incoming: Color, /// Color of outgoing connections - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub outgoing: Color, /// Color of header and footer text - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub text_headers: Color, /// Color of body and buttons text - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub text_body: Color, /// Color of round container borders and scrollbar borders - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub round_borders: Color, /// Color of round containers - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub round_containers: Color, } @@ -95,13 +123,53 @@ impl Default for Palette { } } +impl Hash for Palette { + fn hash(&self, state: &mut H) { + // NOTE: Destructuring Palette here is useful in case the struct gains new fields. + // Rust will helpfully fail to compile due to missing fields. + let Palette { + primary, + secondary, + buttons, + incoming, + outgoing, + text_headers, + text_body, + round_borders, + round_containers, + } = self; + + color_hash(*primary, state); + color_hash(*secondary, state); + color_hash(*buttons, state); + color_hash(*incoming, state); + color_hash(*outgoing, state); + color_hash(*text_headers, state); + color_hash(*text_body, state); + color_hash(*round_borders, state); + color_hash(*round_containers, state); + } +} + /// Extension colors for custom themes. // NOTE: The purpose of this type is primarily to avoid modifying the existing [Palette]. -#[derive(Debug, PartialEq, Deserialize, Serialize)] +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] pub struct PaletteExtension { /// Color of favorites star - #[serde(deserialize_with = "deserialize_color", serialize_with = "serialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub starred: Color, /// Badge alpha channel pub badge_alpha: f32, } + +impl Hash for PaletteExtension { + fn hash(&self, state: &mut H) { + color_hash(self.starred, state); + // f32::NAN is 0i32 when casted using `as`. + let alpha: i32 = (self.badge_alpha * 1000.0).trunc() as i32; + alpha.hash(state); + } +} diff --git a/src/gui/styles/types/style_type.rs b/src/gui/styles/types/style_type.rs index 5d46a48b..98da17bf 100644 --- a/src/gui/styles/types/style_type.rs +++ b/src/gui/styles/types/style_type.rs @@ -1,5 +1,7 @@ use serde::{Deserialize, Serialize}; +use super::custom_style::CustomStyle; + /// Used to specify the kind of style of the application #[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash, PartialEq)] pub enum StyleType { @@ -7,6 +9,7 @@ pub enum StyleType { Day, DeepSea, MonAmour, + // Custom(CustomStyle) } impl Default for StyleType { diff --git a/src/translations/types/language.rs b/src/translations/types/language.rs index 4e3554bc..4c695fc9 100644 --- a/src/translations/types/language.rs +++ b/src/translations/types/language.rs @@ -8,7 +8,7 @@ use crate::countries::flags_pictures::{ }; /// This enum defines the available languages. -#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash, PartialOrd, Ord)] pub enum Language { /// English (default language). EN, From 9540971b4c861ac7f02a7d337e758c4caf027c80 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Thu, 22 Jun 2023 01:53:35 -0400 Subject: [PATCH 05/29] Replace `StyleType` with `Arc`. `StyleType` is no longer `Copy` because the enum holds `CustomStyle`. --- Cargo.toml | 2 +- resources/themes/catppuccin_mocha.toml | 1 + src/chart/types/traffic_chart.rs | 4 +- src/configs/types/config_settings.rs | 4 +- src/countries/country_utils.rs | 14 ++-- src/gui/app.rs | 14 ++-- src/gui/components/footer.rs | 30 ++++---- src/gui/components/header.rs | 18 +++-- src/gui/components/modal.rs | 22 +++--- src/gui/components/radio.rs | 34 +++++---- src/gui/components/tab.rs | 11 +-- src/gui/pages/connection_details_page.rs | 32 ++++---- src/gui/pages/initial_page.rs | 27 ++++--- src/gui/pages/inspect_page.rs | 79 +++++++++++--------- src/gui/pages/notifications_page.rs | 48 ++++++------ src/gui/pages/overview_page.rs | 57 +++++++------- src/gui/pages/settings_language_page.rs | 20 ++--- src/gui/pages/settings_notifications_page.rs | 68 +++++++++-------- src/gui/pages/settings_style_page.rs | 34 +++++---- src/gui/styles/button.rs | 8 +- src/gui/styles/checkbox.rs | 4 +- src/gui/styles/container.rs | 4 +- src/gui/styles/picklist.rs | 6 +- src/gui/styles/radio.rs | 4 +- src/gui/styles/rule.rs | 2 +- src/gui/styles/scrollbar.rs | 4 +- src/gui/styles/slider.rs | 6 +- src/gui/styles/style_constants.rs | 13 ++-- src/gui/styles/text_input.rs | 12 +-- src/gui/styles/types/custom_style.rs | 4 + src/gui/styles/types/palette.rs | 17 +++-- src/gui/styles/types/style_tuple.rs | 6 +- src/gui/styles/types/style_type.rs | 10 ++- src/gui/types/message.rs | 4 +- src/gui/types/sniffer.rs | 72 +++++++++--------- src/report/get_report_entries.rs | 2 +- src/utils/formatted_strings.rs | 6 +- 37 files changed, 381 insertions(+), 322 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f757b727..5de3df10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ iced_lazy = "0.6.1" plotters-iced = "0.8.0" maxminddb = "0.23.0" confy = "0.5.1" -serde = { version = "1.0.163", default_features = false, features = ["derive"] } +serde = { version = "1.0.163", default_features = false, features = ["derive", "rc"] } rodio = { version = "0.17.1", default_features = false, features = ["mp3"] } reqwest = { version = "0.11.18", default-features = false, features = ["json", "blocking", "rustls-tls"] } dns-lookup = "2.0.2" diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index e3885a5a..78e0e83b 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -19,3 +19,4 @@ round_borders = "#74c7ec" # Sapphire round_containers = "#585b70" # Surface 2 starred = "#f9e2af" # Yellow badge_alpha = 0.75 +color_mix_chart = 0.3 diff --git a/src/chart/types/traffic_chart.rs b/src/chart/types/traffic_chart.rs index bf4d7810..fb996ac9 100644 --- a/src/chart/types/traffic_chart.rs +++ b/src/chart/types/traffic_chart.rs @@ -46,7 +46,7 @@ pub struct TrafficChart { } impl TrafficChart { - pub fn new(style: StyleType, language: Language) -> Self { + pub fn new(style: &StyleType, language: Language) -> Self { TrafficChart { ticks: 0, sent_bytes: VecDeque::default(), @@ -89,7 +89,7 @@ impl TrafficChart { self.language = language; } - pub fn change_colors(&mut self, style: StyleType) { + pub fn change_colors(&mut self, style: &StyleType) { self.color_font = to_rgb_color(get_colors(style).text_body); self.color_incoming = to_rgb_color(get_colors(style).incoming); self.color_outgoing = to_rgb_color(get_colors(style).outgoing); diff --git a/src/configs/types/config_settings.rs b/src/configs/types/config_settings.rs index 0f553339..22aef7f5 100644 --- a/src/configs/types/config_settings.rs +++ b/src/configs/types/config_settings.rs @@ -1,6 +1,8 @@ //! Module defining the `ConfigSettings` struct, which allows to save and reload //! the application default configuration. +use std::sync::Arc; + use serde::{Deserialize, Serialize}; use crate::notifications::types::notifications::Notifications; @@ -8,7 +10,7 @@ use crate::{Language, StyleType}; #[derive(Serialize, Deserialize, Default)] pub struct ConfigSettings { - pub style: StyleType, + pub style: Arc, pub language: Language, pub notifications: Notifications, } diff --git a/src/countries/country_utils.rs b/src/countries/country_utils.rs index decd1367..8a8ed893 100644 --- a/src/countries/country_utils.rs +++ b/src/countries/country_utils.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::widget::Tooltip; use iced::{Length, Renderer}; use iced_native::svg::Handle; @@ -332,16 +334,16 @@ pub fn get_flag_tooltip( is_local: bool, traffic_type: TrafficType, language: Language, - style: StyleType, + style: &Arc, ) -> Tooltip<'static, Message> { let (content, tooltip) = get_flag_from_country(country, width, is_local, traffic_type, language); let mut tooltip = Tooltip::new(content, tooltip, Position::FollowCursor) - .font(get_font(style)) + .font(get_font(&style)) .snap_within_viewport(true) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )); if width == FLAGS_WIDTH_SMALL { @@ -355,7 +357,7 @@ pub fn get_computer_tooltip( is_my_address: bool, traffic_type: TrafficType, language: Language, - style: StyleType, + style: &Arc, ) -> Tooltip<'static, Message> { let content = Svg::new(Handle::from_memory(Vec::from( match (is_my_address, traffic_type) { @@ -376,9 +378,9 @@ pub fn get_computer_tooltip( }; Tooltip::new(content, tooltip, Position::FollowCursor) - .font(get_font(style)) + .font(get_font(&style)) .snap_within_viewport(true) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } diff --git a/src/gui/app.rs b/src/gui/app.rs index 6e32b303..f79b8f68 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -49,12 +49,12 @@ impl Application for Sniffer { fn view(&self) -> Element { let status = *self.status_pair.0.lock().unwrap(); - let style = self.style; - let font = get_font(style); + let style = &self.style; + let font = get_font(&style); let header = match status { - Status::Init => header(style, false, self.language, self.last_opened_setting), - Status::Running => header(style, true, self.language, self.last_opened_setting), + Status::Init => header(&style, false, self.language, self.last_opened_setting), + Status::Running => header(&style, true, self.language, self.last_opened_setting), }; let body = match status { @@ -66,7 +66,7 @@ impl Application for Sniffer { }, }; - let footer = footer(self.language, style, &self.newer_release_available.clone()); + let footer = footer(self.language, &style, &self.newer_release_available.clone()); let content = Column::new().push(header).push(body).push(footer); @@ -88,8 +88,8 @@ impl Application for Sniffer { } Some(modal) => { let overlay = match modal { - MyModal::Quit => get_exit_overlay(style, font, self.language), - MyModal::ClearAll => get_clear_all_overlay(style, font, self.language), + MyModal::Quit => get_exit_overlay(&style, font, self.language), + MyModal::ClearAll => get_clear_all_overlay(&style, font, self.language), MyModal::ConnectionDetails(connection_index) => { connection_details_page(self, connection_index) } diff --git a/src/gui/components/footer.rs b/src/gui/components/footer.rs index 5aa3f149..3c2656c4 100644 --- a/src/gui/components/footer.rs +++ b/src/gui/components/footer.rs @@ -22,7 +22,7 @@ use crate::Language; pub fn footer( language: Language, - style: StyleType, + style: &Arc, newer_release_available: &Arc>>, ) -> Container<'static, Message> { let font_footer = get_font_headers(style); @@ -53,11 +53,11 @@ pub fn footer( .align_y(Vertical::Center) .align_x(Horizontal::Center) .style(>::into( - StyleTuple(style, ElementType::Headers), + StyleTuple(Arc::clone(style), ElementType::Headers), )) } -fn get_button_website(style: StyleType) -> Tooltip<'static, Message> { +fn get_button_website(style: &Arc) -> Tooltip<'static, Message> { let content = button( Text::new('c'.to_string()) .font(ICONS) @@ -67,17 +67,17 @@ fn get_button_website(style: StyleType) -> Tooltip<'static, Message> { ) .height(Length::Fixed(30.0)) .width(Length::Fixed(30.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::OpenWebPage(WebPage::Website)); Tooltip::new(content, "Website", Position::Top) - .font(get_font(style)) + .font(get_font(&style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } -fn get_button_github(style: StyleType) -> Tooltip<'static, Message> { +fn get_button_github(style: &Arc) -> Tooltip<'static, Message> { let content = button( Text::new('H'.to_string()) .font(ICONS) @@ -87,17 +87,17 @@ fn get_button_github(style: StyleType) -> Tooltip<'static, Message> { ) .height(Length::Fixed(40.0)) .width(Length::Fixed(40.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::OpenWebPage(WebPage::Repo)); Tooltip::new(content, "GitHub", Position::Top) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } -fn get_button_sponsor(style: StyleType) -> Tooltip<'static, Message> { +fn get_button_sponsor(style: &Arc) -> Tooltip<'static, Message> { let content = button( Text::new('❤'.to_string()) .size(28) @@ -107,19 +107,19 @@ fn get_button_sponsor(style: StyleType) -> Tooltip<'static, Message> { ) .height(Length::Fixed(30.0)) .width(Length::Fixed(30.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::OpenWebPage(WebPage::Sponsor)); Tooltip::new(content, "Sponsor", Position::Top) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } fn get_release_details( language: Language, - style: StyleType, + style: &Arc, font_footer: Font, newer_release_available: &Arc>>, ) -> Row<'static, Message> { @@ -146,7 +146,7 @@ fn get_release_details( .padding(5) .height(Length::Fixed(35.0)) .width(Length::Fixed(35.0)) - .style(StyleTuple(style, ElementType::Alert).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Alert).into()) .on_press(Message::OpenWebPage(WebPage::WebsiteDownload)); let tooltip = Tooltip::new( button, @@ -155,7 +155,7 @@ fn get_release_details( ) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )); ret_val = ret_val .push(horizontal_space(Length::Fixed(10.0))) diff --git a/src/gui/components/header.rs b/src/gui/components/header.rs index c976f1cb..c31e907e 100644 --- a/src/gui/components/header.rs +++ b/src/gui/components/header.rs @@ -1,5 +1,7 @@ //! GUI upper header +use std::sync::Arc; + use iced::alignment::{Horizontal, Vertical}; use iced::widget::{button, Container, Row, Text, Tooltip}; use iced::Length::FillPortion; @@ -15,7 +17,7 @@ use crate::translations::translations::{quit_analysis_translation, settings_tran use crate::{Language, StyleType}; pub fn header( - style: StyleType, + style: &Arc, back_button: bool, language: Language, last_opened_setting: SettingsPage, @@ -61,11 +63,11 @@ pub fn header( .align_y(Vertical::Center) .width(Length::Fill) .style(>::into( - StyleTuple(style, ElementType::Headers), + StyleTuple(Arc::clone(style), ElementType::Headers), )) } -fn get_button_reset(style: StyleType, language: Language) -> Tooltip<'static, Message> { +fn get_button_reset(style: &Arc, language: Language) -> Tooltip<'static, Message> { let content = button( Text::new('C'.to_string()) .font(ICONS) @@ -76,7 +78,7 @@ fn get_button_reset(style: StyleType, language: Language) -> Tooltip<'static, Me .padding(10) .height(Length::Fixed(40.0)) .width(Length::Fixed(60.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::ResetButtonPressed); Tooltip::new( @@ -86,12 +88,12 @@ fn get_button_reset(style: StyleType, language: Language) -> Tooltip<'static, Me ) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } pub fn get_button_settings( - style: StyleType, + style: &Arc, language: Language, open_overlay: SettingsPage, ) -> Tooltip<'static, Message> { @@ -104,12 +106,12 @@ pub fn get_button_settings( .padding(10) .height(Length::Fixed(40.0)) .width(Length::Fixed(60.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::OpenSettings(open_overlay)); Tooltip::new(content, settings_translation(language), Position::Left) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } diff --git a/src/gui/components/modal.rs b/src/gui/components/modal.rs index 24b1c4fc..6eee9a7b 100644 --- a/src/gui/components/modal.rs +++ b/src/gui/components/modal.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::alignment::{Alignment, Horizontal, Vertical}; use iced::widget::{ button, horizontal_space, vertical_space, Column, Container, Row, Text, Tooltip, @@ -18,7 +20,7 @@ use crate::translations::translations::{ use crate::{Language, StyleType}; pub fn get_exit_overlay( - style: StyleType, + style: &Arc, font: Font, language: Language, ) -> Container<'static, Message> { @@ -45,12 +47,12 @@ pub fn get_exit_overlay( .height(Length::Fixed(160.0)) .width(Length::Fixed(450.0)) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )) } pub fn get_clear_all_overlay( - style: StyleType, + style: &Arc, font: Font, language: Language, ) -> Container<'static, Message> { @@ -77,12 +79,12 @@ pub fn get_clear_all_overlay( .height(Length::Fixed(160.0)) .width(Length::Fixed(450.0)) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )) } fn get_modal_header( - style: StyleType, + style: &Arc, language: Language, title: String, ) -> Container<'static, Message> { @@ -111,14 +113,14 @@ fn get_modal_header( .padding(2) .height(Length::Fixed(20.0)) .width(Length::Fixed(20.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::HideModal), tooltip, Position::Right, ) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )), ) .width(Length::FillPortion(1)) @@ -130,14 +132,14 @@ fn get_modal_header( .height(Length::Fixed(40.0)) .width(Length::Fill) .style(>::into( - StyleTuple(style, ElementType::Headers), + StyleTuple(Arc::clone(style), ElementType::Headers), )) } fn confirm_button_row( language: Language, font: Font, - style: StyleType, + style: &Arc, message: Message, ) -> Row<'static, Message> { Row::new() @@ -153,7 +155,7 @@ fn confirm_button_row( .padding(5) .height(Length::Fixed(40.0)) .width(Length::Fixed(80.0)) - .style(StyleTuple(style, ElementType::Alert).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Alert).into()) .on_press(message), ) } diff --git a/src/gui/components/radio.rs b/src/gui/components/radio.rs index c79080af..72d822ac 100644 --- a/src/gui/components/radio.rs +++ b/src/gui/components/radio.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::widget::{Column, Radio, Row, Text}; use iced::{Alignment, Font, Length}; use iced_native::widget::horizontal_space; @@ -18,7 +20,7 @@ use crate::{ChartType, IpVersion, Language, StyleType, TransProtocol}; pub fn ip_version_radios( active: IpVersion, font: Font, - style: StyleType, + style: &Arc, language: Language, ) -> Column<'static, Message> { let mut ret_val = Column::new().spacing(10).padding(0).push( @@ -38,7 +40,7 @@ pub fn ip_version_radios( .font(font) .size(15) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ); @@ -49,7 +51,7 @@ pub fn ip_version_radios( pub fn transport_protocol_radios( active: TransProtocol, font: Font, - style: StyleType, + style: &Arc, language: Language, ) -> Column<'static, Message> { let mut ret_val = Column::new().spacing(10).push( @@ -69,7 +71,7 @@ pub fn transport_protocol_radios( .font(font) .size(15) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ); @@ -81,7 +83,7 @@ pub fn language_radios( active: Language, collection: &[Language], font: Font, - style: StyleType, + style: &Arc, ) -> Row<'static, Message> { let mut ret_val = Row::new().spacing(10); for option in collection { @@ -101,7 +103,7 @@ pub fn language_radios( .size(15) .style( >::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, )), ), @@ -117,7 +119,7 @@ pub fn language_radios( pub fn sound_packets_threshold_radios( packets_notification: PacketsNotification, font: Font, - style: StyleType, + style: &Arc, language: Language, ) -> Row<'static, Message> { let mut ret_val = Row::new() @@ -143,7 +145,7 @@ pub fn sound_packets_threshold_radios( .font(font) .size(15) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ); @@ -154,7 +156,7 @@ pub fn sound_packets_threshold_radios( pub fn sound_bytes_threshold_radios( bytes_notification: BytesNotification, font: Font, - style: StyleType, + style: &Arc, language: Language, ) -> Row<'static, Message> { let mut ret_val = Row::new() @@ -180,7 +182,7 @@ pub fn sound_bytes_threshold_radios( .font(font) .size(15) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ); @@ -191,7 +193,7 @@ pub fn sound_bytes_threshold_radios( pub fn sound_favorite_radios( favorite_notification: FavoriteNotification, font: Font, - style: StyleType, + style: &Arc, language: Language, ) -> Row<'static, Message> { let mut ret_val = Row::new() @@ -217,7 +219,7 @@ pub fn sound_favorite_radios( .font(font) .size(15) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ); @@ -228,7 +230,7 @@ pub fn sound_favorite_radios( pub fn chart_radios( active: ChartType, font: Font, - style: StyleType, + style: &Arc, language: Language, ) -> Column<'static, Message> { let mut ret_val = Column::new() @@ -247,7 +249,7 @@ pub fn chart_radios( .font(font) .size(15) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ); @@ -258,7 +260,7 @@ pub fn chart_radios( // pub fn report_radios( // active: ReportType, // font: Font, -// style: StyleType, +// style: Arc, // language: Language, // ) -> Row<'static, Message> { // let mut ret_val = Row::new() @@ -282,7 +284,7 @@ pub fn chart_radios( // .font(font) // .size(15) // .style(>::into(StyleTuple( -// style, +// Arc::clone(style), // ElementType::Standard, // ))), // ); diff --git a/src/gui/components/tab.rs b/src/gui/components/tab.rs index 62d5e73a..aeb328e0 100644 --- a/src/gui/components/tab.rs +++ b/src/gui/components/tab.rs @@ -1,4 +1,5 @@ //! Tab buttons to be used in the various pages just under the header +use std::sync::Arc; use iced::widget::{button, horizontal_space, Button, Row, Text}; use iced::{alignment, Alignment, Font, Length}; @@ -15,7 +16,7 @@ pub fn get_settings_tabs( icons: &[&str], actions: &[Message], active: SettingsPage, - style: StyleType, + style: &Arc, language: Language, ) -> Row<'static, Message> { let font = get_font(style); @@ -43,7 +44,7 @@ pub fn get_pages_tabs( icons: &[&str], actions: &[Message], active: RunningPage, - style: StyleType, + style: &Arc, language: Language, unread_notifications: usize, ) -> Row<'static, Message> { @@ -77,7 +78,7 @@ fn new_tab( icon: String, action: Message, active: bool, - style: StyleType, + style: &Arc, font: Font, unread: Option, ) -> Button<'static, Message> { @@ -110,7 +111,7 @@ fn new_tab( ) .padding(4) .height(Length::Fixed(20.0)) - .style(StyleTuple(style, ElementType::Badge).into()); + .style(StyleTuple(Arc::clone(style), ElementType::Badge).into()); content = content .push(horizontal_space(Length::Fixed(7.0))) .push(notifications_badge); @@ -124,7 +125,7 @@ fn new_tab( .width(Length::FillPortion(1)) .style( StyleTuple( - style, + Arc::clone(style), if active { ElementType::TabActive } else { diff --git a/src/gui/pages/connection_details_page.rs b/src/gui/pages/connection_details_page.rs index 6238b836..7cb4a6af 100644 --- a/src/gui/pages/connection_details_page.rs +++ b/src/gui/pages/connection_details_page.rs @@ -1,4 +1,4 @@ -use std::net::IpAddr; +use std::{net::IpAddr, sync::Arc}; use iced::alignment::{Horizontal, Vertical}; use iced::widget::{Column, Container, Row, Text, Tooltip}; @@ -38,7 +38,7 @@ pub fn connection_details_page(sniffer: &Sniffer, connection_index: usize) -> Co } fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static, Message> { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let info_traffic_lock = sniffer .info_traffic @@ -61,7 +61,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static let header_and_content = Column::new() .width(Length::Fill) - .push(page_header(sniffer.style, sniffer.language)); + .push(page_header(&sniffer.style, sniffer.language)); let mut source_caption = Row::new().spacing(10).push( Text::new(source_translation(sniffer.language)) @@ -82,7 +82,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static host_info.is_local, host_info.traffic_type, sniffer.language, - sniffer.style, + &sniffer.style, ); if address_to_lookup.eq(&key.address1) { source_caption = source_caption.push(flag); @@ -95,7 +95,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static TrafficDirection::Outgoing, ), sniffer.language, - sniffer.style, + &sniffer.style, ); dest_caption = dest_caption.push(computer); } else { @@ -109,7 +109,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static TrafficDirection::Outgoing, ), sniffer.language, - sniffer.style, + &sniffer.style, ); source_caption = source_caption.push(computer); } @@ -118,7 +118,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static host_info_col.push(Rule::horizontal(10.0).style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), ))); } if r_dns.parse::().is_err() { @@ -152,7 +152,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static ) .push( Rule::horizontal(10.0).style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) .push( @@ -180,7 +180,7 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static ) .push( Rule::horizontal(10.0).style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) .push( @@ -210,14 +210,14 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static .padding(10) .width(Length::Fill) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple(Arc::clone(&sniffer.style), ElementType::BorderedRound), )); let dest_container = Container::new(dest_col) .padding(10) .width(Length::Fill) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple(Arc::clone(&sniffer.style), ElementType::BorderedRound), )); let col_info = Column::new() @@ -291,11 +291,11 @@ fn page_content(sniffer: &Sniffer, connection_index: usize) -> Container<'static .width(Length::Fixed(1000.0)) .height(Length::Fixed(500.0)) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } -fn page_header(style: StyleType, language: Language) -> Container<'static, Message> { +fn page_header(style: &Arc, language: Language) -> Container<'static, Message> { let font = get_font(style); let tooltip = hide_translation(language).to_string(); Container::new( @@ -320,14 +320,14 @@ fn page_header(style: StyleType, language: Language) -> Container<'static, Messa .padding(2) .height(Fixed(20.0)) .width(Fixed(20.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::HideModal), tooltip, Position::Right, ) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )), ) .width(Length::FillPortion(1)) @@ -339,6 +339,6 @@ fn page_header(style: StyleType, language: Language) -> Container<'static, Messa .height(Fixed(40.0)) .width(Length::Fill) .style(>::into( - StyleTuple(style, ElementType::Headers), + StyleTuple(Arc::clone(style), ElementType::Headers), )) } diff --git a/src/gui/pages/initial_page.rs b/src/gui/pages/initial_page.rs index f404a389..35958ee5 100644 --- a/src/gui/pages/initial_page.rs +++ b/src/gui/pages/initial_page.rs @@ -2,6 +2,8 @@ //! //! It contains elements to select network adapter and traffic filters. +use std::sync::Arc; + use iced::widget::{ button, horizontal_space, vertical_space, Button, Column, Container, PickList, Row, Scrollable, Text, Tooltip, @@ -25,12 +27,12 @@ use crate::{AppProtocol, Language, StyleType}; /// Computes the body of gui initial page pub fn initial_page(sniffer: &Sniffer) -> Container { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let col_adapter = get_col_adapter(sniffer, font); let ip_active = sniffer.filters.ip; - let col_ip_radio = ip_version_radios(ip_active, font, sniffer.style, sniffer.language); + let col_ip_radio = ip_version_radios(ip_active, font, &sniffer.style, sniffer.language); let col_ip = Column::new() .spacing(10) .width(FillPortion(5)) @@ -38,14 +40,14 @@ pub fn initial_page(sniffer: &Sniffer) -> Container { let transport_active = sniffer.filters.transport; let col_transport_radio = - transport_protocol_radios(transport_active, font, sniffer.style, sniffer.language); + transport_protocol_radios(transport_active, font, &sniffer.style, sniffer.language); let col_transport = Column::new() .align_items(Alignment::Center) .spacing(10) .width(FillPortion(9)) .push(col_transport_radio) .push(vertical_space(FillPortion(2))) - .push(button_start(sniffer.style, sniffer.language)) + .push(button_start(&sniffer.style, sniffer.language)) .push(vertical_space(FillPortion(1))); let app_active = if sniffer.filters.application.ne(&AppProtocol::Other) { @@ -65,7 +67,10 @@ pub fn initial_page(sniffer: &Sniffer) -> Container { .padding([3, 7]) .placeholder(all_translation(sniffer.language)) .font(font) - .style(StyleTuple(sniffer.style, ElementType::Standard)); + .style(StyleTuple( + Arc::clone(&sniffer.style), + ElementType::Standard, + )); let col_app = Column::new() .width(FillPortion(8)) .spacing(10) @@ -105,13 +110,13 @@ pub fn initial_page(sniffer: &Sniffer) -> Container { Container::new(body).height(Length::Fill).style( >::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, )), ) } -fn button_start(style: StyleType, language: Language) -> Tooltip<'static, Message> { +fn button_start(style: &Arc, language: Language) -> Tooltip<'static, Message> { let content = button( Text::new("S") .font(ICONS) @@ -122,7 +127,7 @@ fn button_start(style: StyleType, language: Language) -> Tooltip<'static, Messag .padding(10) .height(Length::Fixed(80.0)) .width(Length::Fixed(160.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::Start); let tooltip = start_translation(language).to_string(); @@ -131,7 +136,7 @@ fn button_start(style: StyleType, language: Language) -> Tooltip<'static, Messag .gap(5) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } @@ -190,7 +195,7 @@ fn get_col_adapter(sniffer: &Sniffer, font: Font) -> Column { .width(Length::Fill) .style( StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), if name == sniffer.device.name { ElementType::BorderedRoundSelected } else { @@ -204,7 +209,7 @@ fn get_col_adapter(sniffer: &Sniffer, font: Font) -> Column { }, )) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) } diff --git a/src/gui/pages/inspect_page.rs b/src/gui/pages/inspect_page.rs index 7390f3e3..644bc453 100644 --- a/src/gui/pages/inspect_page.rs +++ b/src/gui/pages/inspect_page.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::alignment::Horizontal; use iced::widget::{ Button, Checkbox, Column, Container, PickList, Row, Scrollable, Text, TextInput, Tooltip, @@ -27,7 +29,7 @@ use crate::{Language, ReportSortType, RunningPage, Sniffer, StyleType}; /// Computes the body of gui inspect page pub fn inspect_page(sniffer: &Sniffer) -> Container { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let mut body = Column::new() .width(Length::Fill) @@ -50,7 +52,7 @@ pub fn inspect_page(sniffer: &Sniffer) -> Container { Message::ChangeRunningPage(RunningPage::Notifications), ], RunningPage::Inspect, - sniffer.style, + &sniffer.style, sniffer.language, sniffer.unread_notifications, ); @@ -76,12 +78,15 @@ pub fn inspect_page(sniffer: &Sniffer) -> Container { ) .padding([3, 7]) .font(font) - .style(StyleTuple(sniffer.style, ElementType::Standard)); + .style(StyleTuple( + Arc::clone(&sniffer.style), + ElementType::Standard, + )); let report = lazy( ( sniffer.runtime_data.tot_sent_packets + sniffer.runtime_data.tot_received_packets, - sniffer.style, + Arc::clone(&sniffer.style), sniffer.language, sniffer.report_sort_type, sniffer.search.clone(), @@ -96,12 +101,12 @@ pub fn inspect_page(sniffer: &Sniffer) -> Container { Row::new() .push(filters_col( &sniffer.search, - sniffer.style, + &sniffer.style, sniffer.language, )) .push( Rule::vertical(25).style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) .push( @@ -118,7 +123,7 @@ pub fn inspect_page(sniffer: &Sniffer) -> Container { .height(Length::Fixed(160.0)) .padding(10) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple(Arc::clone(&sniffer.style), ElementType::BorderedRound), )), ) .push(report); @@ -126,12 +131,12 @@ pub fn inspect_page(sniffer: &Sniffer) -> Container { Container::new(Column::new().push(tab_and_body.push(body))) .height(Length::Fill) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let (search_results, results_number) = get_searched_entries(sniffer); @@ -142,7 +147,7 @@ fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { col_report = col_report .push(Text::new(" Src IP address Src port Dst IP address Dst port Layer4 Layer7 Packets Bytes Country").font(font)) .push(Rule::horizontal(20).style(>::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, )))) ; @@ -150,7 +155,7 @@ fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { let start_entry_num = (sniffer.page_number - 1) * 20 + 1; let end_entry_num = start_entry_num + search_results.len() - 1; for (key, val, flag) in search_results { - let entry_color = get_connection_color(val.traffic_direction, sniffer.style); + let entry_color = get_connection_color(val.traffic_direction, &sniffer.style); let entry_row = Row::new() .align_items(Alignment::Center) .push( @@ -165,7 +170,7 @@ fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { button(entry_row) .padding(2) .on_press(Message::ShowModal(MyModal::ConnectionDetails(val.index))) - .style(StyleTuple(sniffer.style, ElementType::Neutral).into()), + .style(StyleTuple(Arc::clone(&sniffer.style), ElementType::Neutral).into()), ); } if results_number > 0 { @@ -176,16 +181,16 @@ fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { .width(Length::Fill) .horizontal_scroll(Properties::new()) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) .push( Rule::horizontal(20).style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) .push(get_change_page_row( - sniffer.style, + &sniffer.style, sniffer.language, sniffer.page_number, start_entry_num, @@ -217,12 +222,12 @@ fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { .padding([10, 7, 7, 7]) .width(Length::Fixed(1042.0)) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple(Arc::clone(&sniffer.style), ElementType::BorderedRound), )), ) .push( Container::new(get_button_open_report( - sniffer.style, + &sniffer.style, sniffer.language, font, )) @@ -232,10 +237,10 @@ fn lazy_report(sniffer: &Sniffer) -> Row<'static, Message> { fn filters_col( search_params: &SearchParameters, - style: StyleType, + style: &Arc, language: Language, ) -> Column<'static, Message> { - let font = get_font(style); + let font = get_font(&style); let search_params2 = search_params.clone(); let mut title_row = Row::new().spacing(10).align_items(Alignment::Center).push( @@ -246,7 +251,7 @@ fn filters_col( if search_params.is_some_filter_active() { title_row = title_row.push(button_clear_filter( SearchParameters::default(), - style, + &style, font, )); } @@ -271,13 +276,13 @@ fn filters_col( .size(18) .font(font) .style(>::into( - StyleTuple(style, ElementType::Badge), + StyleTuple(Arc::clone(style), ElementType::Badge), )), ) .padding([5, 8]) .style(>::into( StyleTuple( - style, + Arc::clone(style), if search_params.only_favorites { ElementType::Badge } else { @@ -297,7 +302,7 @@ fn filters_col( 60.0, search_params.clone(), font, - style, + &style, )) .push(filter_input( FilterInputType::Country, @@ -306,7 +311,7 @@ fn filters_col( 30.0, search_params.clone(), font, - style, + &style, )), ) .push( @@ -320,7 +325,7 @@ fn filters_col( 120.0, search_params.clone(), font, - style, + &style, )) .push(filter_input( FilterInputType::AS, @@ -329,7 +334,7 @@ fn filters_col( 120.0, search_params.clone(), font, - style, + &style, )), ) } @@ -341,7 +346,7 @@ fn filter_input( width: f32, search_params: SearchParameters, font: Font, - style: StyleType, + style: &Arc, ) -> Container<'static, Message> { let is_filter_active = !filter_value.is_empty(); @@ -394,7 +399,7 @@ fn filter_input( .width(Length::Fixed(width)) .style(>::into( StyleTuple( - style, + Arc::clone(style), if is_filter_active { ElementType::Badge } else { @@ -416,7 +421,7 @@ fn filter_input( .padding(5) .style(>::into( StyleTuple( - style, + Arc::clone(style), if is_filter_active { ElementType::Badge } else { @@ -426,7 +431,7 @@ fn filter_input( )) } -fn get_button_change_page(style: StyleType, increment: bool) -> Button<'static, Message> { +fn get_button_change_page(style: &Arc, increment: bool) -> Button<'static, Message> { button( Text::new(if increment { "j" } else { "i" }) .size(10.0) @@ -437,12 +442,12 @@ fn get_button_change_page(style: StyleType, increment: bool) -> Button<'static, .padding(5) .height(Length::Fixed(25.0)) .width(Length::Fixed(25.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::UpdatePageNumber(increment)) } fn get_change_page_row( - style: StyleType, + style: &Arc, language: Language, page_number: usize, start_entry_num: usize, @@ -475,7 +480,7 @@ fn get_change_page_row( } fn get_button_open_report( - style: StyleType, + style: &Arc, language: Language, font: Font, ) -> Tooltip<'static, Message> { @@ -488,20 +493,20 @@ fn get_button_open_report( .padding(10) .height(Length::Fixed(50.0)) .width(Length::Fixed(75.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::OpenReport); Tooltip::new(content, get_open_report_tooltip(language), Position::Top) .gap(5) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } fn button_clear_filter( new_search_parameters: SearchParameters, - style: StyleType, + style: &Arc, font: Font, ) -> Button<'static, Message> { button( @@ -513,6 +518,6 @@ fn button_clear_filter( .padding(2) .height(Length::Fixed(20.0)) .width(Length::Fixed(20.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::Search(new_search_parameters)) } diff --git a/src/gui/pages/notifications_page.rs b/src/gui/pages/notifications_page.rs index 7bf6d751..7f30e7a6 100644 --- a/src/gui/pages/notifications_page.rs +++ b/src/gui/pages/notifications_page.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::alignment::{Horizontal, Vertical}; use iced::widget::{Column, Container, Row, Scrollable, Text, Tooltip}; use iced::Length::FillPortion; @@ -32,7 +34,7 @@ use crate::{Language, RunningPage, Sniffer, StyleType}; /// Computes the body of gui notifications page pub fn notifications_page(sniffer: &Sniffer) -> Container { let notifications = sniffer.notifications; - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let mut tab_and_body = Column::new() .align_items(Alignment::Center) @@ -51,7 +53,7 @@ pub fn notifications_page(sniffer: &Sniffer) -> Container { Message::TickInit, ], RunningPage::Notifications, - sniffer.style, + &sniffer.style, sniffer.language, sniffer.unread_notifications, ); @@ -65,7 +67,7 @@ pub fn notifications_page(sniffer: &Sniffer) -> Container { && !notifications.favorite_notification.notify_on_favorite && sniffer.runtime_data.logged_notifications.is_empty() { - let body = body_no_notifications_set(sniffer.style, font, sniffer.language); + let body = body_no_notifications_set(&sniffer.style, font, sniffer.language); tab_and_body = tab_and_body.push(body); } else if sniffer.runtime_data.logged_notifications.is_empty() { let body = body_no_notifications_received(font, sniffer.language, &sniffer.waiting); @@ -76,7 +78,7 @@ pub fn notifications_page(sniffer: &Sniffer) -> Container { sniffer.runtime_data.tot_emitted_notifications, sniffer.runtime_data.logged_notifications.len(), sniffer.language, - sniffer.style, + Arc::clone(&sniffer.style), ), move |_| lazy_logged_notifications(sniffer), ); @@ -98,12 +100,12 @@ pub fn notifications_page(sniffer: &Sniffer) -> Container { Scrollable::new(logged_notifications).style(>::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, ))), ) .push( - Container::new(get_button_clear_all(sniffer.style, sniffer.language)) + Container::new(get_button_clear_all(&sniffer.style, sniffer.language)) .width(Length::FillPortion(1)) .height(Length::Fill) .align_x(Horizontal::Center) @@ -115,12 +117,12 @@ pub fn notifications_page(sniffer: &Sniffer) -> Container { Container::new(Column::new().push(tab_and_body)) .height(Length::Fill) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } fn body_no_notifications_set( - style: StyleType, + style: &Arc, font: Font, language: Language, ) -> Column<'static, Message> { @@ -166,7 +168,7 @@ fn body_no_notifications_received( fn packets_notification_log( logged_notification: PacketsThresholdExceeded, language: Language, - style: StyleType, + style: &Arc, ) -> Container<'static, Message> { let font = get_font(style); let threshold_str = format!( @@ -195,7 +197,7 @@ fn packets_notification_log( ) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )), ) .push( @@ -229,14 +231,14 @@ fn packets_notification_log( .width(Length::Fixed(800.0)) .padding(10) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )) } fn bytes_notification_log( logged_notification: BytesThresholdExceeded, language: Language, - style: StyleType, + style: &Arc, ) -> Container<'static, Message> { let font = get_font(style); let mut threshold_str = threshold_translation(language); @@ -270,7 +272,7 @@ fn bytes_notification_log( ) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )), ) .push( @@ -306,14 +308,14 @@ fn bytes_notification_log( .width(Length::Fixed(800.0)) .padding(10) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )) } fn favorite_notification_log( logged_notification: FavoriteTransmitted, language: Language, - style: StyleType, + style: &Arc, ) -> Container<'static, Message> { let font = get_font(style); let domain = logged_notification.host.domain; @@ -350,7 +352,7 @@ fn favorite_notification_log( ) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )), ) .push( @@ -376,11 +378,11 @@ fn favorite_notification_log( .width(Length::Fixed(800.0)) .padding(10) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )) } -fn get_button_clear_all(style: StyleType, language: Language) -> Tooltip<'static, Message> { +fn get_button_clear_all(style: &Arc, language: Language) -> Tooltip<'static, Message> { let content = button( Text::new('h'.to_string()) .font(ICONS) @@ -391,14 +393,14 @@ fn get_button_clear_all(style: StyleType, language: Language) -> Tooltip<'static .padding(10) .height(Length::Fixed(50.0)) .width(Length::Fixed(75.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::ShowModal(MyModal::ClearAll)); Tooltip::new(content, clear_all_translation(language), Position::Top) .gap(5) .font(get_font(style)) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )) } @@ -415,21 +417,21 @@ fn lazy_logged_notifications(sniffer: &Sniffer) -> Column<'static, Message> { packets_notification_log( packet_threshold_exceeded.clone(), sniffer.language, - sniffer.style, + &sniffer.style, ) } LoggedNotification::BytesThresholdExceeded(byte_threshold_exceeded) => { bytes_notification_log( byte_threshold_exceeded.clone(), sniffer.language, - sniffer.style, + &sniffer.style, ) } LoggedNotification::FavoriteTransmitted(favorite_transmitted) => { favorite_notification_log( favorite_transmitted.clone(), sniffer.language, - sniffer.style, + &sniffer.style, ) } }); diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs index 385081a8..e0f8bfea 100644 --- a/src/gui/pages/overview_page.rs +++ b/src/gui/pages/overview_page.rs @@ -3,6 +3,8 @@ //! It contains elements to display traffic statistics: chart, detailed connections data //! and overall statistics about the filtered traffic. +use std::sync::Arc; + use iced::alignment::{Horizontal, Vertical}; use iced::widget::{button, vertical_space, Column, Container, Row, Scrollable, Text}; use iced::Length::{Fill, FillPortion}; @@ -41,7 +43,7 @@ use crate::{AppProtocol, ChartType, Language, RunningPage}; /// Computes the body of gui overview page pub fn overview_page(sniffer: &Sniffer) -> Container { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let mut body = Column::new(); let mut tab_and_body = Column::new().height(Length::Fill); @@ -84,7 +86,7 @@ pub fn overview_page(sniffer: &Sniffer) -> Container { Message::ChangeRunningPage(RunningPage::Notifications), ], RunningPage::Overview, - sniffer.style, + &sniffer.style, sniffer.language, sniffer.unread_notifications, ); @@ -120,13 +122,13 @@ pub fn overview_page(sniffer: &Sniffer) -> Container { .align_x(Horizontal::Center) .align_y(Vertical::Center) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple(Arc::clone(&sniffer.style), ElementType::BorderedRound), )); let col_info = lazy( ( total, - sniffer.style, + Arc::clone(&sniffer.style), sniffer.language, sniffer.traffic_chart.chart_type, ), @@ -138,7 +140,7 @@ pub fn overview_page(sniffer: &Sniffer) -> Container { ( filtered, num_favorites, - sniffer.style, + Arc::clone(&sniffer.style), sniffer.language, sniffer.traffic_chart.chart_type, ), @@ -161,7 +163,10 @@ pub fn overview_page(sniffer: &Sniffer) -> Container { .height(Length::Fill) .align_x(Horizontal::Center) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple( + Arc::clone(&sniffer.style), + ElementType::BorderedRound, + ), )), ) .push(col_chart), @@ -186,7 +191,7 @@ pub fn overview_page(sniffer: &Sniffer) -> Container { Container::new(Column::new().push(tab_and_body.push(body))) .height(Length::Fill) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } @@ -291,7 +296,7 @@ fn lazy_row_report(sniffer: &Sniffer) -> Row<'static, Message> { .push(col_host) .push( Rule::vertical(40).style(>::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, ))), ) @@ -302,13 +307,13 @@ fn lazy_row_report(sniffer: &Sniffer) -> Row<'static, Message> { .height(Length::Fill) .width(Length::Fixed(1170.0)) .style(>::into( - StyleTuple(sniffer.style, ElementType::BorderedRound), + StyleTuple(Arc::clone(&sniffer.style), ElementType::BorderedRound), )), ) } fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let chart_type = sniffer.traffic_chart.chart_type; let mut col_host = Column::new() @@ -345,7 +350,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { .width(Length::Fixed(FLAGS_WIDTH_BIG)) .style( StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), if data_info_host.is_favorite { ElementType::Starred } else { @@ -400,7 +405,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { .push(Rule::horizontal(1).style(>::into( - StyleTuple(sniffer.style, ElementType::Incoming), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Incoming), ))), ) .push( @@ -410,7 +415,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { .push(Rule::horizontal(1).style(>::into( - StyleTuple(sniffer.style, ElementType::Outgoing), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Outgoing), ))), ), ); @@ -425,7 +430,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { data_info_host.is_local, data_info_host.traffic_type, sniffer.language, - sniffer.style, + &sniffer.style, )) .push(host_bar); @@ -438,7 +443,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { as_name: host.asn.name.clone(), ..SearchParameters::default() })) - .style(StyleTuple(sniffer.style, ElementType::Neutral).into()), + .style(StyleTuple(Arc::clone(&sniffer.style), ElementType::Neutral).into()), ); } @@ -454,7 +459,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { col_host = col_host.push( Scrollable::new(Container::new(scroll_host).width(Length::Fill)).style( >::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, )), ), @@ -464,7 +469,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { } fn col_app(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let chart_type = sniffer.traffic_chart.chart_type; let mut col_app = Column::new() @@ -527,7 +532,7 @@ fn col_app(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { .push(Rule::horizontal(1).style(>::into( - StyleTuple(sniffer.style, ElementType::Incoming), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Incoming), ))), ) .push( @@ -537,7 +542,7 @@ fn col_app(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { .push(Rule::horizontal(1).style(>::into( - StyleTuple(sniffer.style, ElementType::Outgoing), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Outgoing), ))), ), ); @@ -549,13 +554,13 @@ fn col_app(width: f32, sniffer: &Sniffer) -> Column<'static, Message> { app: format!("{app:?}"), ..SearchParameters::default() })) - .style(StyleTuple(sniffer.style, ElementType::Neutral).into()), + .style(StyleTuple(Arc::clone(&sniffer.style), ElementType::Neutral).into()), ); } col_app = col_app.push( Scrollable::new(Container::new(scroll_app).width(Length::Fill)).style( >::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, )), ), @@ -570,7 +575,7 @@ fn lazy_col_info( dropped: u32, sniffer: &Sniffer, ) -> Column<'static, Message> { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let filtered_bytes = sniffer.runtime_data.tot_sent_bytes + sniffer.runtime_data.tot_received_bytes; @@ -612,7 +617,7 @@ fn lazy_col_info( .push(chart_radios( sniffer.traffic_chart.chart_type, font, - sniffer.style, + &sniffer.style, sniffer.language, )); @@ -675,14 +680,14 @@ fn lazy_col_info( .push(col_device_filters) .push( Rule::vertical(25).style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) .push(col_data_representation), ) .push( Rule::horizontal(25).style(>::into(StyleTuple( - sniffer.style, + Arc::clone(&sniffer.style), ElementType::Standard, ))), ) @@ -690,7 +695,7 @@ fn lazy_col_info( Scrollable::new(col_bytes_packets) .width(Length::Fill) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ) } diff --git a/src/gui/pages/settings_language_page.rs b/src/gui/pages/settings_language_page.rs index f26eb0a1..4b447761 100644 --- a/src/gui/pages/settings_language_page.rs +++ b/src/gui/pages/settings_language_page.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::widget::{Column, Container, Text}; use iced::Length::Fixed; use iced::{Alignment, Length}; @@ -15,17 +17,17 @@ use crate::translations::translations::languages_title_translation; use crate::{Language, Sniffer}; pub fn settings_language_page(sniffer: &Sniffer) -> Container { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let language_active = sniffer.language; let row_language_radio_1 = - language_radios(language_active, &Language::ROW1, font, sniffer.style); + language_radios(language_active, &Language::ROW1, font, &sniffer.style); let row_language_radio_2 = - language_radios(language_active, &Language::ROW2, font, sniffer.style); + language_radios(language_active, &Language::ROW2, font, &sniffer.style); let row_language_radio_3 = - language_radios(language_active, &Language::ROW3, font, sniffer.style); + language_radios(language_active, &Language::ROW3, font, &sniffer.style); let row_language_radio_4 = - language_radios(language_active, &Language::ROW4, font, sniffer.style); + language_radios(language_active, &Language::ROW4, font, &sniffer.style); let col_language_radio_all = Column::new() .spacing(10) .push(row_language_radio_1) @@ -36,7 +38,7 @@ pub fn settings_language_page(sniffer: &Sniffer) -> Container { let mut content = Column::new() .align_items(Alignment::Center) .width(Length::Fill) - .push(settings_header(sniffer.style, sniffer.language)) + .push(settings_header(&sniffer.style, sniffer.language)) .push(get_settings_tabs( [ SettingsPage::Notifications, @@ -50,7 +52,7 @@ pub fn settings_language_page(sniffer: &Sniffer) -> Container { Message::TickInit, ], SettingsPage::Language, - sniffer.style, + &sniffer.style, sniffer.language, )) .push(vertical_space(Fixed(15.0))) @@ -69,7 +71,7 @@ pub fn settings_language_page(sniffer: &Sniffer) -> Container { ) .padding(10.0) .style(>::into( - StyleTuple(sniffer.style, ElementType::Badge), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Badge), )), ); } @@ -78,6 +80,6 @@ pub fn settings_language_page(sniffer: &Sniffer) -> Container { .height(Fixed(400.0)) .width(Fixed(800.0)) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } diff --git a/src/gui/pages/settings_notifications_page.rs b/src/gui/pages/settings_notifications_page.rs index 776b06de..b4848990 100644 --- a/src/gui/pages/settings_notifications_page.rs +++ b/src/gui/pages/settings_notifications_page.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::alignment::{Horizontal, Vertical}; use iced::widget::{ button, horizontal_space, vertical_space, Checkbox, Column, Container, Row, Scrollable, Text, @@ -30,10 +32,10 @@ use crate::translations::translations::{ use crate::{Language, Sniffer, StyleType}; pub fn settings_notifications_page(sniffer: &Sniffer) -> Container { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let mut content = Column::new() .width(Length::Fill) - .push(settings_header(sniffer.style, sniffer.language)) + .push(settings_header(&sniffer.style, sniffer.language)) .push(get_settings_tabs( [ SettingsPage::Notifications, @@ -47,7 +49,7 @@ pub fn settings_notifications_page(sniffer: &Sniffer) -> Container { Message::OpenSettings(SettingsPage::Language), ], SettingsPage::Notifications, - sniffer.style, + &sniffer.style, sniffer.language, )) .push(vertical_space(Fixed(15.0))) @@ -65,7 +67,7 @@ pub fn settings_notifications_page(sniffer: &Sniffer) -> Container { .width(Length::Fill) .push(volume_slider( sniffer.language, - sniffer.style, + &sniffer.style, sniffer.notifications.volume, )) .push( @@ -75,21 +77,21 @@ pub fn settings_notifications_page(sniffer: &Sniffer) -> Container { .push(get_packets_notify( sniffer.notifications.packets_notification, sniffer.language, - sniffer.style, + &sniffer.style, )) .push(get_bytes_notify( sniffer.notifications.bytes_notification, sniffer.language, - sniffer.style, + &sniffer.style, )) .push(get_favorite_notify( sniffer.notifications.favorite_notification, sniffer.language, - sniffer.style, + &sniffer.style, )), ) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )), ); @@ -99,14 +101,14 @@ pub fn settings_notifications_page(sniffer: &Sniffer) -> Container { .height(Fixed(400.0)) .width(Fixed(800.0)) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } fn get_packets_notify( packets_notification: PacketsNotification, language: Language, - style: StyleType, + style: &Arc, ) -> Column<'static, Message> { let font = get_font(style); let checkbox = Checkbox::new( @@ -135,7 +137,7 @@ fn get_packets_notify( .size(18) .font(font) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )); let mut ret_val = Column::new().spacing(5).push(checkbox); @@ -146,7 +148,7 @@ fn get_packets_notify( .padding(10) .width(Fixed(700.0)) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )), ) } else { @@ -172,7 +174,7 @@ fn get_packets_notify( .padding(10) .width(Fixed(700.0)) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )), ) } @@ -181,7 +183,7 @@ fn get_packets_notify( fn get_bytes_notify( bytes_notification: BytesNotification, language: Language, - style: StyleType, + style: &Arc, ) -> Column<'static, Message> { let font = get_font(style); let checkbox = Checkbox::new( @@ -210,7 +212,7 @@ fn get_bytes_notify( .size(18) .font(font) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )); let mut ret_val = Column::new().spacing(5).push(checkbox); @@ -221,7 +223,7 @@ fn get_bytes_notify( .padding(10) .width(Fixed(700.0)) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )), ) } else { @@ -247,7 +249,7 @@ fn get_bytes_notify( .padding(10) .width(Fixed(700.0)) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )), ) } @@ -256,7 +258,7 @@ fn get_bytes_notify( fn get_favorite_notify( favorite_notification: FavoriteNotification, language: Language, - style: StyleType, + style: &Arc, ) -> Column<'static, Message> { let font = get_font(style); let checkbox = Checkbox::new( @@ -276,7 +278,7 @@ fn get_favorite_notify( .size(18) .font(font) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )); let mut ret_val = Column::new().spacing(5).push(checkbox); @@ -296,7 +298,7 @@ fn get_favorite_notify( .padding(10) .width(Fixed(700.0)) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )), ) } else { @@ -305,7 +307,7 @@ fn get_favorite_notify( .padding(10) .width(Fixed(700.0)) .style(>::into( - StyleTuple(style, ElementType::BorderedRound), + StyleTuple(Arc::clone(style), ElementType::BorderedRound), )), ) } @@ -313,7 +315,7 @@ fn get_favorite_notify( fn input_group_packets( packets_notification: PacketsNotification, - style: StyleType, + style: &Arc, language: Language, ) -> Container<'static, Message> { let font = get_font(style); @@ -341,7 +343,7 @@ fn input_group_packets( .font(font) .width(Length::Fixed(100.0)) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )), ) .push( @@ -357,7 +359,7 @@ fn input_group_packets( fn input_group_bytes( bytes_notification: BytesNotification, - style: StyleType, + style: &Arc, language: Language, ) -> Container<'static, Message> { let font = get_font(style); @@ -386,7 +388,7 @@ fn input_group_bytes( .font(font) .width(Length::Fixed(100.0)) .style(>::into( - StyleTuple(style, ElementType::Standard), + StyleTuple(Arc::clone(style), ElementType::Standard), )), ) .push( @@ -400,7 +402,11 @@ fn input_group_bytes( .align_y(Vertical::Center) } -fn volume_slider(language: Language, style: StyleType, volume: u8) -> Container<'static, Message> { +fn volume_slider( + language: Language, + style: &Arc, + volume: u8, +) -> Container<'static, Message> { let font = get_font(style); Container::new( Column::new() @@ -421,7 +427,7 @@ fn volume_slider(language: Language, style: StyleType, volume: u8) -> Container< .step(5) .width(Fixed(200.0)) .style(>::into(StyleTuple( - style, + Arc::clone(style), ElementType::Standard, ))), ) @@ -441,7 +447,7 @@ fn volume_slider(language: Language, style: StyleType, volume: u8) -> Container< .align_y(Vertical::Center) } -pub fn settings_header(style: StyleType, language: Language) -> Container<'static, Message> { +pub fn settings_header(style: &Arc, language: Language) -> Container<'static, Message> { let font = get_font(style); let tooltip = hide_translation(language).to_string(); //tooltip.push_str(" [esc]"); @@ -467,14 +473,14 @@ pub fn settings_header(style: StyleType, language: Language) -> Container<'stati .padding(2) .height(Fixed(20.0)) .width(Fixed(20.0)) - .style(StyleTuple(style, ElementType::Standard).into()) + .style(StyleTuple(Arc::clone(style), ElementType::Standard).into()) .on_press(Message::CloseSettings), tooltip, Position::Right, ) .font(font) .style(>::into( - StyleTuple(style, ElementType::Tooltip), + StyleTuple(Arc::clone(style), ElementType::Tooltip), )), ) .width(Length::FillPortion(1)) @@ -486,6 +492,6 @@ pub fn settings_header(style: StyleType, language: Language) -> Container<'stati .height(Fixed(40.0)) .width(Length::Fill) .style(>::into( - StyleTuple(style, ElementType::Headers), + StyleTuple(Arc::clone(style), ElementType::Headers), )) } diff --git a/src/gui/pages/settings_style_page.rs b/src/gui/pages/settings_style_page.rs index 9064d8ac..8eccc2ea 100644 --- a/src/gui/pages/settings_style_page.rs +++ b/src/gui/pages/settings_style_page.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use iced::widget::{Button, Column, Container, Row, Text}; use iced::{Alignment, Length}; use iced_native::svg::Handle; @@ -20,11 +22,11 @@ use crate::StyleType::{Day, DeepSea, MonAmour, Night}; use crate::{Sniffer, StyleType}; pub fn settings_style_page(sniffer: &Sniffer) -> Container { - let font = get_font(sniffer.style); + let font = get_font(&sniffer.style); let content = Column::new() .align_items(Alignment::Center) .width(Length::Fill) - .push(settings_header(sniffer.style, sniffer.language)) + .push(settings_header(&sniffer.style, sniffer.language)) .push(get_settings_tabs( [ SettingsPage::Notifications, @@ -38,7 +40,7 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { Message::OpenSettings(SettingsPage::Language), ], SettingsPage::Appearance, - sniffer.style, + &sniffer.style, sniffer.language, )) .push(vertical_space(Length::Fixed(15.0))) @@ -51,38 +53,38 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { .push( Row::new() .push(get_palette_container( - sniffer.style, + &sniffer.style, YETI_NIGHT, "Yeti Night".to_string(), yeti_night_translation(sniffer.language).to_string(), - Night, + &Arc::new(Night), )) .push(horizontal_space(Length::Fixed(15.0))) .push(get_palette_container( - sniffer.style, + &sniffer.style, YETI_DAY, "Yeti Day".to_string(), yeti_day_translation(sniffer.language).to_string(), - Day, + &Arc::new(Day), )), ) .push(vertical_space(Length::Fixed(10.0))) .push( Row::new() .push(get_palette_container( - sniffer.style, + &sniffer.style, DEEP_SEA, "Deep Sea".to_string(), deep_sea_translation(sniffer.language).to_string(), - DeepSea, + &Arc::new(DeepSea), )) .push(horizontal_space(Length::Fixed(15.0))) .push(get_palette_container( - sniffer.style, + &sniffer.style, MON_AMOUR, "Mon Amour".to_string(), mon_amour_translation(sniffer.language).to_string(), - MonAmour, + &Arc::new(MonAmour), )), ); @@ -90,16 +92,16 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { .height(Length::Fixed(400.0)) .width(Length::Fixed(800.0)) .style(>::into( - StyleTuple(sniffer.style, ElementType::Standard), + StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), )) } fn get_palette_container( - style: StyleType, + style: &Arc, picture: &[u8], name: String, description: String, - on_press: StyleType, + on_press: &Arc, ) -> Button<'static, Message> { let font = get_font(style); let content = Column::new() @@ -116,7 +118,7 @@ fn get_palette_container( .padding(5) .style( StyleTuple( - style, + Arc::clone(style), if on_press.eq(&style) { ElementType::BorderedRoundSelected } else { @@ -125,5 +127,5 @@ fn get_palette_container( ) .into(), ) - .on_press(Message::Style(on_press)) + .on_press(Message::Style(Arc::clone(on_press))) } diff --git a/src/gui/styles/button.rs b/src/gui/styles/button.rs index b3487632..44780b6c 100644 --- a/src/gui/styles/button.rs +++ b/src/gui/styles/button.rs @@ -20,11 +20,11 @@ impl button::StyleSheet for StyleTuple { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> button::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); button::Appearance { background: Some(Background::Color(match self { StyleTuple(_, ElementType::TabActive) => colors.primary, - StyleTuple(_, ElementType::Starred) => get_starred_color(self.0), + StyleTuple(_, ElementType::Starred) => get_starred_color(&self.0), StyleTuple(_, ElementType::Badge) => colors.secondary, StyleTuple(_, ElementType::BorderedRound) => colors.round_containers, StyleTuple(_, ElementType::Neutral | ElementType::NotStarred) => Color::TRANSPARENT, @@ -72,14 +72,14 @@ impl button::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style) -> button::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); button::Appearance { shadow_offset: match self.1 { ElementType::Neutral => Vector::default(), _ => Vector::new(0.0, 2.0), }, background: Some(Background::Color(match self { - StyleTuple(_, ElementType::Starred) => get_starred_color(self.0), + StyleTuple(_, ElementType::Starred) => get_starred_color(&self.0), StyleTuple(_, ElementType::TabActive) => colors.primary, _ => mix_colors(colors.primary, colors.buttons), })), diff --git a/src/gui/styles/checkbox.rs b/src/gui/styles/checkbox.rs index f15a3cc1..a219db2c 100644 --- a/src/gui/styles/checkbox.rs +++ b/src/gui/styles/checkbox.rs @@ -17,7 +17,7 @@ impl iced::widget::checkbox::StyleSheet for StyleTuple { type Style = iced::Theme; fn active(&self, _: &Self::Style, is_checked: bool) -> Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { background: Background::Color(colors.buttons), icon_color: colors.text_body, @@ -29,7 +29,7 @@ impl iced::widget::checkbox::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style, _is_checked: bool) -> Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { background: Background::Color(colors.buttons), icon_color: colors.text_body, diff --git a/src/gui/styles/container.rs b/src/gui/styles/container.rs index 036e6394..154e4cb2 100644 --- a/src/gui/styles/container.rs +++ b/src/gui/styles/container.rs @@ -21,7 +21,7 @@ impl iced::widget::container::StyleSheet for StyleTuple { type Style = Theme; fn appearance(&self, _: &Self::Style) -> Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { text_color: Some(match self { StyleTuple(_, ElementType::Headers) => colors.text_headers, @@ -33,7 +33,7 @@ impl iced::widget::container::StyleSheet for StyleTuple { StyleTuple(_, ElementType::BorderedRound) => colors.round_containers, StyleTuple(_, ElementType::Neutral) => Color::TRANSPARENT, StyleTuple(_, ElementType::Badge) => Color { - a: get_color_mix_filter_badge(self.0), + a: get_color_mix_filter_badge(&self.0), ..colors.secondary }, _ => colors.primary, diff --git a/src/gui/styles/picklist.rs b/src/gui/styles/picklist.rs index b1de8f7b..455bcdf9 100644 --- a/src/gui/styles/picklist.rs +++ b/src/gui/styles/picklist.rs @@ -19,7 +19,7 @@ impl iced::overlay::menu::StyleSheet for StyleTuple { type Style = iced::Theme; fn appearance(&self, _: &Self::Style) -> iced::overlay::menu::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); iced::overlay::menu::Appearance { text_color: colors.text_body, background: Background::Color(colors.buttons), @@ -36,7 +36,7 @@ impl pick_list::StyleSheet for StyleTuple { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> pick_list::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); pick_list::Appearance { text_color: colors.text_body, placeholder_color: colors.text_body, @@ -49,7 +49,7 @@ impl pick_list::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style) -> pick_list::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); pick_list::Appearance { text_color: colors.text_body, placeholder_color: colors.text_body, diff --git a/src/gui/styles/radio.rs b/src/gui/styles/radio.rs index 09862665..7bc072cd 100644 --- a/src/gui/styles/radio.rs +++ b/src/gui/styles/radio.rs @@ -17,7 +17,7 @@ impl iced::widget::radio::StyleSheet for StyleTuple { type Style = Theme; fn active(&self, _: &Self::Style, is_selected: bool) -> iced::widget::radio::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); iced::widget::radio::Appearance { background: Background::Color(colors.buttons), dot_color: colors.secondary, @@ -28,7 +28,7 @@ impl iced::widget::radio::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style, _is_selected: bool) -> iced::widget::radio::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); iced::widget::radio::Appearance { background: Background::Color(colors.buttons), dot_color: colors.secondary, diff --git a/src/gui/styles/rule.rs b/src/gui/styles/rule.rs index a17e8954..1b07fd6e 100644 --- a/src/gui/styles/rule.rs +++ b/src/gui/styles/rule.rs @@ -17,7 +17,7 @@ impl rule::StyleSheet for StyleTuple { type Style = iced::Theme; fn appearance(&self, _: &Self::Style) -> iced::widget::rule::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); iced::widget::rule::Appearance { color: match self.1 { ElementType::Incoming => colors.secondary, diff --git a/src/gui/styles/scrollbar.rs b/src/gui/styles/scrollbar.rs index 58605df0..fda6d931 100644 --- a/src/gui/styles/scrollbar.rs +++ b/src/gui/styles/scrollbar.rs @@ -18,7 +18,7 @@ impl iced::widget::scrollable::StyleSheet for StyleTuple { type Style = Theme; fn active(&self, _: &Self::Style) -> Scrollbar { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Scrollbar { background: Some(Background::Color(colors.round_borders)), border_radius: BORDER_ROUNDED_RADIUS, @@ -34,7 +34,7 @@ impl iced::widget::scrollable::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style, is_mouse_over_scrollbar: bool) -> Scrollbar { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Scrollbar { background: Some(Background::Color(colors.round_borders)), border_radius: BORDER_ROUNDED_RADIUS, diff --git a/src/gui/styles/slider.rs b/src/gui/styles/slider.rs index 5bffcf80..51dc33d9 100644 --- a/src/gui/styles/slider.rs +++ b/src/gui/styles/slider.rs @@ -19,7 +19,7 @@ impl iced::widget::slider::StyleSheet for StyleTuple { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { rail: Rail { colors: (colors.secondary, colors.buttons), @@ -35,7 +35,7 @@ impl iced::widget::slider::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style) -> Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { rail: Rail { colors: (colors.secondary, colors.buttons), @@ -51,7 +51,7 @@ impl iced::widget::slider::StyleSheet for StyleTuple { } fn dragging(&self, _: &Self::Style) -> Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { rail: Rail { colors: (colors.secondary, colors.buttons), diff --git a/src/gui/styles/style_constants.rs b/src/gui/styles/style_constants.rs index d4c1a922..373b5407 100644 --- a/src/gui/styles/style_constants.rs +++ b/src/gui/styles/style_constants.rs @@ -166,24 +166,25 @@ pub const SARASA_MONO_SC_BOLD: Font = Font::External { bytes: include_bytes!("../../../resources/fonts/subset/sarasa-mono-sc-bold.subset.ttf"), }; -pub fn get_font(style: StyleType) -> Font { +pub fn get_font(style: &StyleType) -> Font { match to_rgb_color(get_colors(style).text_body) { RGBColor(255, 255, 255) => Font::Default, _ => SARASA_MONO_SC_BOLD, } } -pub fn get_font_headers(style: StyleType) -> Font { +pub fn get_font_headers(style: &StyleType) -> Font { match to_rgb_color(get_colors(style).text_headers) { RGBColor(255, 255, 255) => Font::Default, _ => SARASA_MONO_SC_BOLD, } } -pub fn get_color_mix_chart(style: StyleType) -> f64 { +pub fn get_color_mix_chart(style: &StyleType) -> f64 { match style { StyleType::Night | StyleType::DeepSea => 0.3, StyleType::Day | StyleType::MonAmour => 0.8, + StyleType::Custom(style) => style.palette.extension.color_mix_chart, } } @@ -212,7 +213,7 @@ pub const BORDER_ROUNDED_RADIUS: f32 = 15.0; pub const BORDER_BUTTON_RADIUS: f32 = 180.0; /// Yellow color used in favorites star -pub fn get_starred_color(style: StyleType) -> Color { +pub fn get_starred_color(style: &StyleType) -> Color { match style { StyleType::Night | StyleType::DeepSea => Color { r: 245.0 / 255.0, @@ -226,13 +227,15 @@ pub fn get_starred_color(style: StyleType) -> Color { b: 39.0 / 255.0, a: 0.8, }, + StyleType::Custom(style) => style.palette.extension.starred, } } -pub fn get_color_mix_filter_badge(style: StyleType) -> f32 { +pub fn get_color_mix_filter_badge(style: &StyleType) -> f32 { match style { StyleType::Night | StyleType::DeepSea => 0.2, StyleType::Day => 0.7, StyleType::MonAmour => 0.5, + StyleType::Custom(style) => style.palette.extension.badge_alpha, } } diff --git a/src/gui/styles/text_input.rs b/src/gui/styles/text_input.rs index 5aa5f843..c604b907 100644 --- a/src/gui/styles/text_input.rs +++ b/src/gui/styles/text_input.rs @@ -18,7 +18,7 @@ impl iced::widget::text_input::StyleSheet for StyleTuple { type Style = iced::Theme; fn active(&self, _: &Self::Style) -> iced::widget::text_input::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { background: Background::Color(match self.1 { ElementType::Badge => Color::TRANSPARENT, @@ -35,7 +35,7 @@ impl iced::widget::text_input::StyleSheet for StyleTuple { } fn focused(&self, _: &Self::Style) -> iced::widget::text_input::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { background: Background::Color(colors.primary), border_radius: 0.0, @@ -46,7 +46,7 @@ impl iced::widget::text_input::StyleSheet for StyleTuple { } fn placeholder_color(&self, _: &Self::Style) -> Color { - let color = get_colors(self.0).text_body; + let color = get_colors(&self.0).text_body; Color { a: if color.eq(&Color::BLACK) { 0.7 } else { 0.2 }, ..color @@ -54,7 +54,7 @@ impl iced::widget::text_input::StyleSheet for StyleTuple { } fn value_color(&self, _: &Self::Style) -> Color { - get_colors(self.0).text_body + get_colors(&self.0).text_body } fn disabled_color(&self, _style: &Self::Style) -> Color { @@ -62,7 +62,7 @@ impl iced::widget::text_input::StyleSheet for StyleTuple { } fn selection_color(&self, _: &Self::Style) -> Color { - let color = get_colors(self.0).text_body; + let color = get_colors(&self.0).text_body; Color { a: if color.eq(&Color::BLACK) { 0.4 } else { 0.05 }, ..color @@ -70,7 +70,7 @@ impl iced::widget::text_input::StyleSheet for StyleTuple { } fn hovered(&self, _: &Self::Style) -> iced::widget::text_input::Appearance { - let colors = get_colors(self.0); + let colors = get_colors(&self.0); Appearance { background: Background::Color(match self.1 { ElementType::Badge => Color::TRANSPARENT, diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 2cb8e92c..c1d3cd60 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -72,6 +72,7 @@ impl PartialEq for CustomPalette { let PaletteExtension { starred, badge_alpha, + color_mix_chart, } = self.extension; // Other @@ -90,6 +91,7 @@ impl PartialEq for CustomPalette { let PaletteExtension { starred: starred_other, badge_alpha: badge_alpha_other, + color_mix_chart: color_mix_chart_other, } = other.extension; color_partialeq(primary, primary_other) @@ -103,6 +105,7 @@ impl PartialEq for CustomPalette { && color_partialeq(round_containers, round_containers_other) && color_partialeq(starred, starred_other) && badge_alpha == badge_alpha_other + && color_mix_chart == color_mix_chart_other } } @@ -254,6 +257,7 @@ mod tests { a: 1.0, }, badge_alpha: 0.75, + color_mix_chart: 0.3, }, }, }) diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 0fd076a9..a271aaee 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -78,12 +78,13 @@ pub struct Palette { pub round_containers: Color, } -pub fn get_colors(style: StyleType) -> Palette { +pub fn get_colors(style: &StyleType) -> &Palette { match style { - StyleType::Night => NIGHT_STYLE, - StyleType::Day => DAY_STYLE, - StyleType::DeepSea => DEEP_SEA_STYLE, - StyleType::MonAmour => MON_AMOUR_STYLE, + StyleType::Night => &NIGHT_STYLE, + StyleType::Day => &DAY_STYLE, + StyleType::DeepSea => &DEEP_SEA_STYLE, + StyleType::MonAmour => &MON_AMOUR_STYLE, + StyleType::Custom(style) => &style.palette.base, } } @@ -119,7 +120,7 @@ pub fn mix_colors(color_1: Color, color_2: Color) -> Color { impl Default for Palette { fn default() -> Self { - get_colors(StyleType::Night) + get_colors(&StyleType::Night).clone() } } @@ -163,6 +164,8 @@ pub struct PaletteExtension { pub starred: Color, /// Badge alpha channel pub badge_alpha: f32, + /// Color mixing for charts + pub color_mix_chart: f64, } impl Hash for PaletteExtension { @@ -171,5 +174,7 @@ impl Hash for PaletteExtension { // f32::NAN is 0i32 when casted using `as`. let alpha: i32 = (self.badge_alpha * 1000.0).trunc() as i32; alpha.hash(state); + let color_mix: i32 = (self.color_mix_chart * 1000.0).trunc() as i32; + color_mix.hash(state) } } diff --git a/src/gui/styles/types/style_tuple.rs b/src/gui/styles/types/style_tuple.rs index 9b146266..3f494b78 100644 --- a/src/gui/styles/types/style_tuple.rs +++ b/src/gui/styles/types/style_tuple.rs @@ -1,11 +1,13 @@ +use std::sync::Arc; + use crate::gui::styles::types::element_type::ElementType; use crate::StyleType; /// This tuple permits to specify the correct style depending on the style type and on the element type -pub struct StyleTuple(pub StyleType, pub ElementType); +pub struct StyleTuple(pub Arc, pub ElementType); impl Clone for StyleTuple { fn clone(&self) -> Self { - Self(self.0, self.1) + Self(Arc::clone(&self.0), self.1) } } diff --git a/src/gui/styles/types/style_type.rs b/src/gui/styles/types/style_type.rs index 98da17bf..c94d9621 100644 --- a/src/gui/styles/types/style_type.rs +++ b/src/gui/styles/types/style_type.rs @@ -1,15 +1,19 @@ use serde::{Deserialize, Serialize}; -use super::custom_style::CustomStyle; +use super::custom_style::{deserialize_from_path, serialize_to_path, CustomStyle}; /// Used to specify the kind of style of the application -#[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash, PartialEq)] +#[derive(Clone, Serialize, Deserialize, Debug, Hash, PartialEq)] pub enum StyleType { Night, Day, DeepSea, MonAmour, - // Custom(CustomStyle) + #[serde( + serialize_with = "serialize_to_path", + deserialize_with = "deserialize_from_path" + )] + Custom(CustomStyle), } impl Default for StyleType { diff --git a/src/gui/types/message.rs b/src/gui/types/message.rs index 229fed37..2ffea05e 100644 --- a/src/gui/types/message.rs +++ b/src/gui/types/message.rs @@ -1,3 +1,5 @@ +use std::sync::Arc; + use crate::gui::components::types::my_modal::MyModal; use crate::gui::pages::types::running_page::RunningPage; use crate::gui::pages::types::settings_page::SettingsPage; @@ -39,7 +41,7 @@ pub enum Message { /// Stop sniffing process and return to initial page Reset, /// Change application style - Style(StyleType), + Style(Arc), /// Manage waiting time Waiting, /// Displays a modal diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index f5365b1a..6fdbfaeb 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -54,7 +54,7 @@ pub struct Sniffer { /// Signals if a pcap error occurred pub pcap_error: Option, /// Application style (only values Day and Night are possible for this field) - pub style: StyleType, + pub style: Arc, /// Waiting string pub waiting: String, /// Chart displayed @@ -102,9 +102,9 @@ impl Sniffer { last_device_name_sniffed: config_device.device_name.clone(), filters: Filters::default(), pcap_error: None, - style: config_settings.style, + style: Arc::clone(&config_settings.style), waiting: ".".to_string(), - traffic_chart: TrafficChart::new(config_settings.style, config_settings.language), + traffic_chart: TrafficChart::new(&config_settings.style, config_settings.language), report_sort_type: ReportSortType::MostRecent, modal: None, settings_page: None, @@ -139,7 +139,7 @@ impl Sniffer { Message::Reset => return self.reset(), Message::Style(style) => { self.style = style; - self.traffic_chart.change_colors(self.style); + self.traffic_chart.change_colors(&self.style); } Message::Waiting => self.update_waiting_dots(), Message::AddOrRemoveFavorite(host, add) => self.add_or_remove_favorite(&host, add), @@ -315,7 +315,7 @@ impl Sniffer { let info_traffic_mutex = self.info_traffic.clone(); *info_traffic_mutex.lock().unwrap() = InfoTraffic::new(); self.runtime_data = RunTimeData::new(); - self.traffic_chart = TrafficChart::new(self.style, self.language); + self.traffic_chart = TrafficChart::new(&self.style, self.language); if pcap_error.is_none() { // no pcap error @@ -390,7 +390,7 @@ impl Sniffer { self.last_opened_setting = self.settings_page.unwrap(); self.settings_page = None; let store = ConfigSettings { - style: self.style, + style: Arc::clone(&self.style), notifications: self.notifications, language: self.language, }; @@ -643,95 +643,95 @@ mod tests { Arc::new(Mutex::new(Err(String::new()))), ); - sniffer.update(Message::Style(StyleType::MonAmour)); - assert_eq!(sniffer.style, StyleType::MonAmour); + sniffer.update(Message::Style(Arc::new(StyleType::MonAmour))); + assert_eq!(*sniffer.style, StyleType::MonAmour); assert_eq!( sniffer.traffic_chart.color_font, - to_rgb_color(get_colors(StyleType::MonAmour).text_body) + to_rgb_color(get_colors(&StyleType::MonAmour).text_body) ); assert_eq!( sniffer.traffic_chart.color_outgoing, - to_rgb_color(get_colors(StyleType::MonAmour).outgoing) + to_rgb_color(get_colors(&StyleType::MonAmour).outgoing) ); assert_eq!( sniffer.traffic_chart.color_incoming, - to_rgb_color(get_colors(StyleType::MonAmour).secondary) + to_rgb_color(get_colors(&StyleType::MonAmour).secondary) ); assert_eq!( sniffer.traffic_chart.color_mix, - get_color_mix_chart(StyleType::MonAmour) + get_color_mix_chart(&StyleType::MonAmour) ); - sniffer.update(Message::Style(StyleType::Day)); - assert_eq!(sniffer.style, StyleType::Day); + sniffer.update(Message::Style(Arc::new(StyleType::Day))); + assert_eq!(*sniffer.style, StyleType::Day); assert_eq!( sniffer.traffic_chart.color_font, - to_rgb_color(get_colors(StyleType::Day).text_body) + to_rgb_color(get_colors(&StyleType::Day).text_body) ); assert_eq!( sniffer.traffic_chart.color_outgoing, - to_rgb_color(get_colors(StyleType::Day).outgoing) + to_rgb_color(get_colors(&StyleType::Day).outgoing) ); assert_eq!( sniffer.traffic_chart.color_incoming, - to_rgb_color(get_colors(StyleType::Day).secondary) + to_rgb_color(get_colors(&StyleType::Day).secondary) ); assert_eq!( sniffer.traffic_chart.color_mix, - get_color_mix_chart(StyleType::Day) + get_color_mix_chart(&StyleType::Day) ); - sniffer.update(Message::Style(StyleType::Night)); - assert_eq!(sniffer.style, StyleType::Night); + sniffer.update(Message::Style(Arc::new(StyleType::Night))); + assert_eq!(*sniffer.style, StyleType::Night); assert_eq!( sniffer.traffic_chart.color_font, - to_rgb_color(get_colors(StyleType::Night).text_body) + to_rgb_color(get_colors(&StyleType::Night).text_body) ); assert_eq!( sniffer.traffic_chart.color_outgoing, - to_rgb_color(get_colors(StyleType::Night).outgoing) + to_rgb_color(get_colors(&StyleType::Night).outgoing) ); assert_eq!( sniffer.traffic_chart.color_incoming, - to_rgb_color(get_colors(StyleType::Night).secondary) + to_rgb_color(get_colors(&StyleType::Night).secondary) ); assert_eq!( sniffer.traffic_chart.color_mix, - get_color_mix_chart(StyleType::Night) + get_color_mix_chart(&StyleType::Night) ); - sniffer.update(Message::Style(StyleType::DeepSea)); - assert_eq!(sniffer.style, StyleType::DeepSea); + sniffer.update(Message::Style(Arc::new(StyleType::DeepSea))); + assert_eq!(*sniffer.style, StyleType::DeepSea); assert_eq!( sniffer.traffic_chart.color_font, - to_rgb_color(get_colors(StyleType::DeepSea).text_body) + to_rgb_color(get_colors(&StyleType::DeepSea).text_body) ); assert_eq!( sniffer.traffic_chart.color_outgoing, - to_rgb_color(get_colors(StyleType::DeepSea).outgoing) + to_rgb_color(get_colors(&StyleType::DeepSea).outgoing) ); assert_eq!( sniffer.traffic_chart.color_incoming, - to_rgb_color(get_colors(StyleType::DeepSea).secondary) + to_rgb_color(get_colors(&StyleType::DeepSea).secondary) ); assert_eq!( sniffer.traffic_chart.color_mix, - get_color_mix_chart(StyleType::DeepSea) + get_color_mix_chart(&StyleType::DeepSea) ); - sniffer.update(Message::Style(StyleType::DeepSea)); - assert_eq!(sniffer.style, StyleType::DeepSea); + sniffer.update(Message::Style(Arc::new(StyleType::DeepSea))); + assert_eq!(*sniffer.style, StyleType::DeepSea); assert_eq!( sniffer.traffic_chart.color_font, - to_rgb_color(get_colors(StyleType::DeepSea).text_body) + to_rgb_color(get_colors(&StyleType::DeepSea).text_body) ); assert_eq!( sniffer.traffic_chart.color_outgoing, - to_rgb_color(get_colors(StyleType::DeepSea).outgoing) + to_rgb_color(get_colors(&StyleType::DeepSea).outgoing) ); assert_eq!( sniffer.traffic_chart.color_incoming, - to_rgb_color(get_colors(StyleType::DeepSea).secondary) + to_rgb_color(get_colors(&StyleType::DeepSea).secondary) ); assert_eq!( sniffer.traffic_chart.color_mix, - get_color_mix_chart(StyleType::DeepSea) + get_color_mix_chart(&StyleType::DeepSea) ); } diff --git a/src/report/get_report_entries.rs b/src/report/get_report_entries.rs index 51a7f689..d75927f1 100644 --- a/src/report/get_report_entries.rs +++ b/src/report/get_report_entries.rs @@ -142,7 +142,7 @@ pub fn get_searched_entries( host_info.is_local, host_info.traffic_type, sniffer.language, - sniffer.style, + &sniffer.style, ); (key_val.0.clone(), key_val.1.clone(), flag) }) diff --git a/src/utils/formatted_strings.rs b/src/utils/formatted_strings.rs index 7ac575c5..d3167abc 100644 --- a/src/utils/formatted_strings.rs +++ b/src/utils/formatted_strings.rs @@ -56,11 +56,11 @@ pub fn get_active_filters_string(filters: &Filters, language: Language) -> Strin } /// Returns the color to be used for a specific connection of the relevant connections table in gui run page -pub fn get_connection_color(traffic_direction: TrafficDirection, style: StyleType) -> Color { +pub fn get_connection_color(traffic_direction: TrafficDirection, style: &StyleType) -> Color { if traffic_direction == TrafficDirection::Outgoing { - get_colors(style).outgoing + get_colors(&style).outgoing } else { - get_colors(style).incoming + get_colors(&style).incoming } } From 3daee4d375f9a0b3f334939a53e887db9875dace Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Sun, 25 Jun 2023 23:59:42 -0400 Subject: [PATCH 06/29] Add a `TextInput` to load custom themes. Iced doesn't provide a file dialog to use because that should be handled natively or something. See [iced-rs/iced#347]. --- resources/themes/catppuccin_mocha.toml | 4 +- src/countries/country_utils.rs | 4 +- src/gui/app.rs | 12 +++--- src/gui/components/footer.rs | 2 +- src/gui/pages/inspect_page.rs | 12 +++--- src/gui/pages/settings_style_page.rs | 25 ++++++++++- src/gui/styles/types/custom_style.rs | 57 +++++++++++++++++--------- src/gui/styles/types/mod.rs | 2 +- src/gui/types/message.rs | 6 +++ src/gui/types/sniffer.rs | 26 ++++++++++++ src/utils/formatted_strings.rs | 4 +- 11 files changed, 113 insertions(+), 41 deletions(-) diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index 78e0e83b..0641465c 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -10,10 +10,10 @@ PL = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps:// [palette] primary = "#1e1e2e" # Base secondary = "#89b4fa" # Blue -buttons = "#89dceb" # Sky +buttons = "#313244" # Surface0 incoming = "#89b4fa" # Blue outgoing = "#f5c2e7" # Pink -text_headers = "#cdd6f4" # Text +text_headers = "#11111b" # Crust text_body = "#cdd6f4" # Text round_borders = "#74c7ec" # Sapphire round_containers = "#585b70" # Surface 2 diff --git a/src/countries/country_utils.rs b/src/countries/country_utils.rs index 8a8ed893..ce14e822 100644 --- a/src/countries/country_utils.rs +++ b/src/countries/country_utils.rs @@ -340,7 +340,7 @@ pub fn get_flag_tooltip( get_flag_from_country(country, width, is_local, traffic_type, language); let mut tooltip = Tooltip::new(content, tooltip, Position::FollowCursor) - .font(get_font(&style)) + .font(get_font(style)) .snap_within_viewport(true) .style(>::into( StyleTuple(Arc::clone(style), ElementType::Tooltip), @@ -378,7 +378,7 @@ pub fn get_computer_tooltip( }; Tooltip::new(content, tooltip, Position::FollowCursor) - .font(get_font(&style)) + .font(get_font(style)) .snap_within_viewport(true) .style(>::into( StyleTuple(Arc::clone(style), ElementType::Tooltip), diff --git a/src/gui/app.rs b/src/gui/app.rs index f79b8f68..b0bb3a0a 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -50,11 +50,11 @@ impl Application for Sniffer { fn view(&self) -> Element { let status = *self.status_pair.0.lock().unwrap(); let style = &self.style; - let font = get_font(&style); + let font = get_font(style); let header = match status { - Status::Init => header(&style, false, self.language, self.last_opened_setting), - Status::Running => header(&style, true, self.language, self.last_opened_setting), + Status::Init => header(style, false, self.language, self.last_opened_setting), + Status::Running => header(style, true, self.language, self.last_opened_setting), }; let body = match status { @@ -66,7 +66,7 @@ impl Application for Sniffer { }, }; - let footer = footer(self.language, &style, &self.newer_release_available.clone()); + let footer = footer(self.language, style, &self.newer_release_available.clone()); let content = Column::new().push(header).push(body).push(footer); @@ -88,8 +88,8 @@ impl Application for Sniffer { } Some(modal) => { let overlay = match modal { - MyModal::Quit => get_exit_overlay(&style, font, self.language), - MyModal::ClearAll => get_clear_all_overlay(&style, font, self.language), + MyModal::Quit => get_exit_overlay(style, font, self.language), + MyModal::ClearAll => get_clear_all_overlay(style, font, self.language), MyModal::ConnectionDetails(connection_index) => { connection_details_page(self, connection_index) } diff --git a/src/gui/components/footer.rs b/src/gui/components/footer.rs index 3c2656c4..48373a3a 100644 --- a/src/gui/components/footer.rs +++ b/src/gui/components/footer.rs @@ -71,7 +71,7 @@ fn get_button_website(style: &Arc) -> Tooltip<'static, Message> { .on_press(Message::OpenWebPage(WebPage::Website)); Tooltip::new(content, "Website", Position::Top) - .font(get_font(&style)) + .font(get_font(style)) .style(>::into( StyleTuple(Arc::clone(style), ElementType::Tooltip), )) diff --git a/src/gui/pages/inspect_page.rs b/src/gui/pages/inspect_page.rs index 644bc453..2992b4b1 100644 --- a/src/gui/pages/inspect_page.rs +++ b/src/gui/pages/inspect_page.rs @@ -240,7 +240,7 @@ fn filters_col( style: &Arc, language: Language, ) -> Column<'static, Message> { - let font = get_font(&style); + let font = get_font(style); let search_params2 = search_params.clone(); let mut title_row = Row::new().spacing(10).align_items(Alignment::Center).push( @@ -251,7 +251,7 @@ fn filters_col( if search_params.is_some_filter_active() { title_row = title_row.push(button_clear_filter( SearchParameters::default(), - &style, + style, font, )); } @@ -302,7 +302,7 @@ fn filters_col( 60.0, search_params.clone(), font, - &style, + style, )) .push(filter_input( FilterInputType::Country, @@ -311,7 +311,7 @@ fn filters_col( 30.0, search_params.clone(), font, - &style, + style, )), ) .push( @@ -325,7 +325,7 @@ fn filters_col( 120.0, search_params.clone(), font, - &style, + style, )) .push(filter_input( FilterInputType::AS, @@ -334,7 +334,7 @@ fn filters_col( 120.0, search_params.clone(), font, - &style, + style, )), ) } diff --git a/src/gui/pages/settings_style_page.rs b/src/gui/pages/settings_style_page.rs index 8eccc2ea..7fd37ee1 100644 --- a/src/gui/pages/settings_style_page.rs +++ b/src/gui/pages/settings_style_page.rs @@ -5,6 +5,8 @@ use iced::{Alignment, Length}; use iced_native::svg::Handle; use iced_native::widget::{horizontal_space, vertical_space, Svg}; +use iced::widget::TextInput; + use crate::gui::components::tab::get_settings_tabs; use crate::gui::pages::settings_notifications_page::settings_header; use crate::gui::pages::types::settings_page::SettingsPage; @@ -86,10 +88,29 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { mon_amour_translation(sniffer.language).to_string(), &Arc::new(MonAmour), )), + ) + .push(vertical_space(Length::Fixed(10.0))) + .push( + Row::new().push( + TextInput::new( + "Path to custom theme and hit enter!", + sniffer.style_path_update.as_deref().unwrap_or_default(), + ) + .font(font) + // Iced's TextInput has an on_submit function but there's no callback + .on_input(Message::UpdateStylePath) + .on_paste(Message::PasteCustomStyle) + .on_submit(Message::LoadCustomStyle) + .padding(10) + .style(StyleTuple( + Arc::clone(&sniffer.style), + ElementType::Standard, + )), + ), ); Container::new(content) - .height(Length::Fixed(400.0)) + .height(Length::Fixed(440.0)) .width(Length::Fixed(800.0)) .style(>::into( StyleTuple(Arc::clone(&sniffer.style), ElementType::Standard), @@ -119,7 +140,7 @@ fn get_palette_container( .style( StyleTuple( Arc::clone(style), - if on_press.eq(&style) { + if on_press.eq(style) { ElementType::BorderedRoundSelected } else { ElementType::BorderedRound diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index c1d3cd60..28bd40a2 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -36,6 +36,35 @@ pub struct CustomStyle { pub palette: CustomPalette, } +impl CustomStyle { + /// Deserialize [CustomStyle] from `path`. + /// + /// # Arguments + /// * `path` - Path to a UTF-8 encoded file containing a custom style as TOML. + pub fn from_file

(path: P) -> Result + where + P: Into, + { + // Try to open the file at `path` + let path = path.into(); + let mut toml_reader = File::open(&path) + .map_err(DeErrorTrait::custom) + .map(BufReader::new)?; + + // Read the ostensible TOML + let mut style_toml = String::new(); + toml_reader + .read_to_string(&mut style_toml) + .map_err(DeErrorTrait::custom)?; + + // Deserialize it and store `path` into the resulting struct + toml::de::from_str::(&style_toml).map(|mut style| { + style.path = path; + style + }) + } +} + /// Base [Palette] and extension colors for [CustomStyle]. // NOTE: This is flattened for ergonomics. With flatten, both [Palette] and [PaletteExtension] can be // defined in the TOML as a single entity rather than two separate tables. This is intentional because @@ -112,24 +141,13 @@ impl PartialEq for CustomPalette { /// Deserialize [CustomStyle] from a file path. /// /// This is implemented by first deserializing a file path which in turn contains the style as TOML. +#[inline] pub(super) fn deserialize_from_path<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, { let path = String::deserialize(deserializer)?; - let mut toml_reader = File::open(&path) - .map_err(DeErrorTrait::custom) - .map(BufReader::new)?; - let mut style_toml = String::new(); - toml_reader - .read_to_string(&mut style_toml) - .map_err(DeErrorTrait::custom)?; - toml::de::from_str::(&style_toml) - .map_err(DeErrorTrait::custom) - .map(|mut style| { - style.path = path; - style - }) + CustomStyle::from_file(path).map_err(DeErrorTrait::custom) } /// Serialize [CustomStyle]'s path. @@ -183,6 +201,7 @@ mod tests { // Polish translation by Bartosz. const STYLE_DESC_PL: &str = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin"; + // NOTE: This has to be updated if `resources/themes/catppuccin_mocha.toml` changes fn catppuccin_style() -> StyleForTests { StyleForTests(CustomStyle { name: "Catppuccin (Mocha)".to_owned(), @@ -207,9 +226,9 @@ mod tests { a: 1.0, }, buttons: Color { - r: 137.0 / 255.0, - g: 220.0 / 255.0, - b: 235.0 / 255.0, + r: 49.0 / 255.0, + g: 50.0 / 255.0, + b: 68.0 / 255.0, a: 1.0, }, incoming: Color { @@ -225,9 +244,9 @@ mod tests { a: 1.0, }, text_headers: Color { - r: 205.0 / 255.0, - g: 214.0 / 255.0, - b: 244.0 / 255.0, + r: 17.0 / 255.0, + g: 17.0 / 255.0, + b: 27.0 / 255.0, a: 1.0, }, text_body: Color { diff --git a/src/gui/styles/types/mod.rs b/src/gui/styles/types/mod.rs index 9204a6cd..46937005 100644 --- a/src/gui/styles/types/mod.rs +++ b/src/gui/styles/types/mod.rs @@ -1,5 +1,5 @@ pub(super) mod color_remote; -pub(super) mod custom_style; +pub mod custom_style; pub mod element_type; pub mod palette; pub mod style_tuple; diff --git a/src/gui/types/message.rs b/src/gui/types/message.rs index 2ffea05e..d760db45 100644 --- a/src/gui/types/message.rs +++ b/src/gui/types/message.rs @@ -42,6 +42,12 @@ pub enum Message { Reset, /// Change application style Style(Arc), + /// Update custom style path + UpdateStylePath(String), + /// Handle a custom style path + PasteCustomStyle(String), + /// Load custom style from a path + LoadCustomStyle, /// Manage waiting time Waiting, /// Displays a modal diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index 6fdbfaeb..2edd2de7 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -13,6 +13,7 @@ use crate::chart::manage_chart_data::update_charts_data; use crate::gui::components::types::my_modal::MyModal; use crate::gui::pages::types::running_page::RunningPage; use crate::gui::pages::types::settings_page::SettingsPage; +use crate::gui::styles::types::custom_style::CustomStyle; use crate::gui::types::message::Message; use crate::gui::types::status::Status; use crate::networking::manage_packets::get_capture_result; @@ -55,6 +56,8 @@ pub struct Sniffer { pub pcap_error: Option, /// Application style (only values Day and Night are possible for this field) pub style: Arc, + /// Receiver for custom style path input on the settings page + pub style_path_update: Option, /// Waiting string pub waiting: String, /// Chart displayed @@ -103,6 +106,7 @@ impl Sniffer { filters: Filters::default(), pcap_error: None, style: Arc::clone(&config_settings.style), + style_path_update: None, waiting: ".".to_string(), traffic_chart: TrafficChart::new(&config_settings.style, config_settings.language), report_sort_type: ReportSortType::MostRecent, @@ -141,6 +145,28 @@ impl Sniffer { self.style = style; self.traffic_chart.change_colors(&self.style); } + Message::UpdateStylePath(keys) => { + if let Some(path) = &mut self.style_path_update { + *path = keys + } else { + self.style_path_update.replace(keys); + } + } + Message::PasteCustomStyle(path) => { + self.style_path_update.replace(path); + return self.update(Message::LoadCustomStyle); + } + Message::LoadCustomStyle => { + // Purposefully ignoring the error because this bit of code will be called on on_input repeatedly. + // This entire bit of code should be much cleaner once we use file dialogs + dbg!(&self.style_path_update); + let style = + CustomStyle::from_file(self.style_path_update.as_deref().unwrap_or_default()) + .map(|style| Arc::new(StyleType::Custom(style))); + if let Ok(style) = style { + return self.update(Message::Style(style)); + } + } Message::Waiting => self.update_waiting_dots(), Message::AddOrRemoveFavorite(host, add) => self.add_or_remove_favorite(&host, add), Message::ShowModal(modal) => { diff --git a/src/utils/formatted_strings.rs b/src/utils/formatted_strings.rs index d3167abc..e2e36df0 100644 --- a/src/utils/formatted_strings.rs +++ b/src/utils/formatted_strings.rs @@ -58,9 +58,9 @@ pub fn get_active_filters_string(filters: &Filters, language: Language) -> Strin /// Returns the color to be used for a specific connection of the relevant connections table in gui run page pub fn get_connection_color(traffic_direction: TrafficDirection, style: &StyleType) -> Color { if traffic_direction == TrafficDirection::Outgoing { - get_colors(&style).outgoing + get_colors(style).outgoing } else { - get_colors(&style).incoming + get_colors(style).incoming } } From 939997679c7424d172d6c2eb3d97df98d32a0ee3 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Mon, 26 Jun 2023 01:32:40 -0400 Subject: [PATCH 07/29] Update README.md with custom style info. (Also, remove a debug line). --- README.md | 67 ++++++++++++++++++++++------ src/gui/styles/types/custom_style.rs | 25 +++++++++++ src/gui/types/sniffer.rs | 8 ++-- 3 files changed, 82 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f530b2c7..93bea83a 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,12 @@

-

+

 

-

+

Application to comfortably monitor your Internet traffic
Multithreaded, cross-platform, reliable
🌐 www.sniffnet.net @@ -78,17 +78,17 @@ You can install Sniffnet in one of the following ways: [32-bit](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_Windows_32-bit.msi) ### macOS - + - [Intel](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_macOS_Intel.dmg) | [Apple silicon](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_macOS_AppleSilicon.dmg) ### Linux - deb: [amd64](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxDEB_amd64.deb) | -[arm64](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxDEB_arm64.deb) | +[arm64](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxDEB_arm64.deb) | [i386](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxDEB_i386.deb) | [armhf](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxDEB_armhf.deb) - + - rpm: [x86_64](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxRPM_x86_64.rpm) | [aarch64](https://github.com/GyulyVGC/sniffnet/releases/latest/download/Sniffnet_LinuxRPM_aarch64.rpm) @@ -221,7 +221,7 @@ sudo sniffnet - 🌍 get information about the country of the remote hosts (IP geolocation) - ⭐ save your favorite network hosts - 🔉 set custom notifications to inform you when defined network events occur -- 🎨 choose the style that fits you the most from 4 different available themes +- 🎨 choose the style that fits you the most from 4 different available themes plus custom theme support - 🕵️ inspect each of your network connections in real time - 📁 save complete textual reports with detailed information for each network connection: * source and destination IP addresses @@ -243,13 +243,13 @@ sudo sniffnet Geolocation and network providers (ASN) refer to the remote IP address of each connection. They are retrieved performing lookups against [MMDB files](https://maxmind.github.io/MaxMind-DB/): > **Note** - > + > > The MMDB (MaxMind database) format has been developed especially for IP lookup.
> It is optimized to perform lookups on data indexed by IP network ranges quickly and efficiently.
> It permits the best performance on IP lookups, and it's suitable for use in a production environment. - > + > > This product includes GeoLite2 data created by MaxMind, available from https://www.maxmind.com - + This file format potentially allows Sniffnet to execute hundreds of different IP lookups in a matter of a few milliseconds. @@ -260,23 +260,23 @@ sudo sniffnet

See details - +
- + Application layer protocols are inferred from the transport port numbers, following the convention maintained by [IANA](https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml). Please, remember that this is just a convention: > **Warning** - > + > > The Internet Assigned Numbers Authority (IANA) is responsible for maintaining > the official assignments of port numbers for specific uses.
> However, many unofficial uses of well-known port numbers occur in practice. The following table reports the port-to-service mappings used by Sniffnet, chosen from the most common assignments by IANA. - +
|Port number(s)|Application protocol | Description | @@ -348,6 +348,45 @@ The currently usable hotkeys are reported in the following.
+## Custom themes +
+ + See details + + Custom themes are specified as a TOML file that may be loaded from anywhere. Themes support multilingual + descriptions. + + The TOML must follow this format: + ```toml + name = "Catppuccin (Mocha)" + + [description] + EN = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin" + # Contributed by Emilia + HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" + # Contributed by Bartosz + PL = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin" + + # Color palettes are in RGBA hexadecimal where the alpha is optional. + [palette] + primary = "#1e1e2e" # Base + secondary = "#89b4fa" # Blue + buttons = "#313244" # Surface0 + incoming = "#89b4fa" # Blue + outgoing = "#f5c2e7" # Pink + text_headers = "#11111b" # Crust + text_body = "#cdd6f4" # Text + round_borders = "#74c7ec" # Sapphire + round_containers = "#585b70" # Surface 2 + starred = "#f9e2af" # Yellow + + # Alpha channels are floats within [0.0, 1.0] + badge_alpha = 0.75 + color_mix_chart = 0.3 + ``` + + The example theme above uses colors from [Catppuccin Mocha](https://github.com/catppuccin/catppuccin). +
## Troubleshooting @@ -388,7 +427,7 @@ Reach out to me, and I'll try to generate an installer for your specific operati In some cases, especially if you are running on an old architecture, the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) may cause some problems that could prevent you from running Sniffnet.
-In this case, you can try building the application from the [`glow-renderer`](https://github.com/GyulyVGC/sniffnet/tree/glow-renderer) +In this case, you can try building the application from the [`glow-renderer`](https://github.com/GyulyVGC/sniffnet/tree/glow-renderer) branch, which uses the `glow` renderer. > **Note** diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 28bd40a2..a71d2cfe 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -1,6 +1,31 @@ //! Custom Sniffnet color schemes. //! Themes should be in TOML files with the following schema. //! ```toml +//! name = "Theme's name" +//! +//! [description] +//! # Descriptions of the theme in any of Sniffnet's supported languages +//! # CODE = "DESC" +//! EN = "A fantastically dark theme!" +//! HU = "" +//! PL = "" +//! +//! # The palette is specified in RGB hexadecimal with an optional alpha +//! [palette] +//! primary = "#000000" +//! secondary = "#000000" +//! buttons = "#000000" +//! incoming = "#000000" +//! outgoing = "#000000" +//! text_headers = "#000000" +//! text_body = "#000000" +//! round_borders = "#000000" +//! round_containers = "#000000" +//! starred = "#000000" +//! +//! # floats for these two alpha values +//! badge_alpha = 0.9 +//! color_mix_chart = 0.3 //! ``` use serde::{de::Error as DeErrorTrait, Deserialize, Deserializer, Serialize, Serializer}; diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index 2edd2de7..1f2d2b61 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -145,11 +145,11 @@ impl Sniffer { self.style = style; self.traffic_chart.change_colors(&self.style); } - Message::UpdateStylePath(keys) => { + Message::UpdateStylePath(value) => { if let Some(path) = &mut self.style_path_update { - *path = keys + *path = value } else { - self.style_path_update.replace(keys); + self.style_path_update.replace(value); } } Message::PasteCustomStyle(path) => { @@ -159,7 +159,7 @@ impl Sniffer { Message::LoadCustomStyle => { // Purposefully ignoring the error because this bit of code will be called on on_input repeatedly. // This entire bit of code should be much cleaner once we use file dialogs - dbg!(&self.style_path_update); + // dbg!(&self.style_path_update); let style = CustomStyle::from_file(self.style_path_update.as_deref().unwrap_or_default()) .map(|style| Arc::new(StyleType::Custom(style))); From 1ec0c6eec2d217c766cb2f7e14eb9eb498fdf8ad Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Tue, 27 Jun 2023 01:19:53 -0400 Subject: [PATCH 08/29] Clean up: use iced::color! --- Cargo.lock | 791 +++++++++++++-------------- src/gui/styles/types/custom_style.rs | 72 +-- 2 files changed, 397 insertions(+), 466 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c6bbfc96..24ea2bcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,9 +52,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "0.7.20" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" dependencies = [ "memchr", ] @@ -113,9 +113,9 @@ dependencies = [ [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" @@ -125,15 +125,15 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ash" -version = "0.37.2+1.3.238" +version = "0.37.3+1.3.251" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28bf19c1f0a470be5fbf7522a308a05df06610252c5bcf5143e1b23f629a9a03" +checksum = "39e9c3835d686b0a6084ab4234fcd1b07dbf6e4767dce60874b12356a25ecd4a" dependencies = [ "libloading 0.7.4", ] @@ -154,22 +154,22 @@ dependencies = [ "cc", "cfg-if", "libc", - "miniz_oxide", + "miniz_oxide 0.6.2", "object", "rustc-demangle", ] [[package]] name = "base64" -version = "0.21.0" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" +checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" [[package]] name = "bindgen" -version = "0.61.0" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a022e58a142a46fea340d68012b9201c094e93ec3d033a944a24f8fd4a4f09a" +checksum = "c4243e6031260db77ede97ad86c27e501d646a27ab57b59a574f725d98ab1fb4" dependencies = [ "bitflags", "cexpr", @@ -214,28 +214,28 @@ checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1" [[package]] name = "bytemuck" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c041d3eab048880cb0b86b256447da3f18859a163c3b8d8893f4e6368abe6393" +checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aca418a974d83d40a0c1f0c5cba6ff4bc28d8df099109ca459a2118d40b6322" +checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -252,10 +252,11 @@ checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" [[package]] name = "calloop" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a59225be45a478d772ce015d9743e49e92798ece9e34eda9a6aa2a6a7f40192" +checksum = "52e0d00eb1ea24371a97d2da6201c6747a633dc6dc1988ef503403b4c59504a8" dependencies = [ + "bitflags", "log", "nix 0.25.1", "slotmap", @@ -307,9 +308,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.0" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ed9a53e5d4d9c573ae844bfac6872b159cb1d1585a83b29e7a64b7eef7332a" +checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" dependencies = [ "glob", "libc", @@ -359,9 +360,9 @@ dependencies = [ [[package]] name = "cmake" -version = "0.1.49" +version = "0.1.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db34956e100b30725f2eb215f90d4871051239535632f84fea3bc92722c66b7c" +checksum = "a31c789563b815f77f4250caee12365734369f942439b7defd71e18a48197130" dependencies = [ "cc", ] @@ -384,9 +385,9 @@ dependencies = [ [[package]] name = "cocoa-foundation" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ade49b65d560ca58c403a479bb396592b155c0185eada742ee323d1d68d6318" +checksum = "931d3837c286f56e3c58423ce4eba12d08db2374461a785c86f672b08b5650d6" dependencies = [ "bitflags", "block", @@ -443,9 +444,9 @@ dependencies = [ [[package]] name = "const_panic" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58baae561b85ca19b3122a9ddd35c8ec40c3bcd14fe89921824eae73f7baffbf" +checksum = "6051f239ecec86fde3410901ab7860d458d160371533842974fc61f96d15879b" [[package]] name = "core-foundation" @@ -453,7 +454,7 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ - "core-foundation-sys 0.8.3", + "core-foundation-sys 0.8.4", "libc", ] @@ -465,9 +466,9 @@ checksum = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b" [[package]] name = "core-foundation-sys" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" [[package]] name = "core-graphics" @@ -484,13 +485,12 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" +checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" dependencies = [ "bitflags", "core-foundation", - "foreign-types 0.3.2", "libc", ] @@ -519,37 +519,36 @@ dependencies = [ [[package]] name = "coreaudio-sys" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a9444b94b8024feecc29e01a9706c69c1e26bfee480221c90764200cfd778fb" +checksum = "f034b2258e6c4ade2f73bf87b21047567fb913ee9550837c2316d139b0262b24" dependencies = [ "bindgen", ] [[package]] name = "cpal" -version = "0.15.0" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34fa7b20adf588f73f094cd9b1d944977c686e37a2759ea217ab174f017e10a" +checksum = "6d959d90e938c5493000514b446987c07aed46c668faaa7d34d6c7a67b1a578c" dependencies = [ "alsa", - "core-foundation-sys 0.8.3", + "core-foundation-sys 0.8.4", "coreaudio-rs", "dasp_sample", "jni 0.19.0", "js-sys", "libc", - "mach", + "mach2", "ndk", "ndk-context", "oboe", "once_cell", "parking_lot 0.12.1", - "thiserror", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "windows", + "windows 0.46.0", ] [[package]] @@ -584,22 +583,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.8.0", + "memoffset 0.9.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" dependencies = [ "cfg-if", ] @@ -612,7 +611,7 @@ checksum = "21fd3add36ea31aba1520aa5288714dd63be506106753226d0eb387a93bc9c45" dependencies = [ "cocoa", "core-foundation", - "core-foundation-sys 0.8.3", + "core-foundation-sys 0.8.4", "core-graphics", "core-text", "dwrote", @@ -633,50 +632,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b365fabc795046672053e29c954733ec3b05e4be654ab130fe8f1f94d7051f35" -[[package]] -name = "cxx" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62" -dependencies = [ - "cc", - "cxxbridge-flags", - "cxxbridge-macro", - "link-cplusplus", -] - -[[package]] -name = "cxx-build" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690" -dependencies = [ - "cc", - "codespan-reporting", - "once_cell", - "proc-macro2", - "quote", - "scratch", - "syn 1.0.109", -] - -[[package]] -name = "cxxbridge-flags" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf" - -[[package]] -name = "cxxbridge-macro" -version = "1.0.91" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "d3d12" version = "0.6.0" @@ -763,11 +718,11 @@ checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" [[package]] name = "dlib" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1b7517328c04c2aa68422fc60a41b92208182142ed04a25879c26c8f878794" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" dependencies = [ - "libloading 0.7.4", + "libloading 0.8.0", ] [[package]] @@ -849,6 +804,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "equivalent" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88bffebc5d80432c9b140ee17875ff173a8ab62faad5b257da912bd2f6c1c0a1" + [[package]] name = "errno" version = "0.2.8" @@ -886,14 +847,14 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "827292ea592108849932ad8e30218f8b1f21c0dfd0696698a18b5d0aed62d990" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", ] [[package]] name = "euclid" -version = "0.22.7" +version = "0.22.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b52c2ef4a78da0ba68fbe1fd920627411096d2ac478f7f4c9f3a54ba6705bade" +checksum = "87f253bc5c813ca05792837a0ff4b3a580336b224512d48f7eda1d7dd9210787" dependencies = [ "num-traits", ] @@ -908,6 +869,15 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "fdeflate" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d329bdeac514ee06249dabc27877490f17f5d371ec693360768b838e19f3ae10" +dependencies = [ + "simd-adler32", +] + [[package]] name = "find-crate" version = "0.6.3" @@ -919,12 +889,12 @@ dependencies = [ [[package]] name = "flate2" -version = "1.0.25" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" dependencies = [ "crc32fast", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -990,13 +960,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8469d0d40519bc608ec6863f1cc88f3f1deee15913f2f3b3e573d81ed38cccc" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -1013,9 +983,9 @@ checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" [[package]] name = "form_urlencoded" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" dependencies = [ "percent-encoding", ] @@ -1044,9 +1014,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "531ac96c6ff5fd7c62263c5e3c67a603af4fcaee2e1a0ae5565ba3a11e69e549" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" dependencies = [ "futures-channel", "futures-core", @@ -1059,9 +1029,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164713a5a0dcc3e7b4b1ed7d3b433cabc18025386f9339346e8daf15963cf7ac" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" dependencies = [ "futures-core", "futures-sink", @@ -1069,15 +1039,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86d7a0c1aa76363dac491de0ee99faf6941128376f1cf96f07db7603b7de69dd" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" [[package]] name = "futures-executor" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1997dd9df74cdac935c76252744c1ed5794fac083242ea4fe77ef3ed60ba0f83" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" dependencies = [ "futures-core", "futures-task", @@ -1087,32 +1057,32 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89d422fa3cbe3b40dca574ab087abb5bc98258ea57eea3fd6f1fa7162c778b91" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" [[package]] name = "futures-macro" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb14ed937631bd8b8b8977f2c198443447a8355b6e3ca599f38c975e5a963b6" +checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] name = "futures-sink" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec93083a4aecafb2a80a885c9de1f0ccae9dbd32c2bb54b0c3a65690e0b8d2f2" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" [[package]] name = "futures-task" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd65540d33b37b16542a0438c12e6aeead10d4ac5d05bd3f805b8f35ab592879" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" [[package]] name = "futures-timer" @@ -1122,9 +1092,9 @@ checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" [[package]] name = "futures-util" -version = "0.3.27" +version = "0.3.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef6b17e481503ec85211fed8f39d1970f128935ca1f814cd32ac4a6842e84ab" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" dependencies = [ "futures-channel", "futures-core", @@ -1159,9 +1129,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" dependencies = [ "cfg-if", "libc", @@ -1180,9 +1150,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.2" +version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" [[package]] name = "glam" @@ -1210,9 +1180,9 @@ dependencies = [ [[package]] name = "glow" -version = "0.12.1" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e007a07a24de5ecae94160f141029e9a347282cfe25d1d58d85d845cf3130f1" +checksum = "807edf58b70c0b5b2181dd39fe1839dbdb3ba02645630dc5f753e23da307f762" dependencies = [ "js-sys", "slotmap", @@ -1272,9 +1242,9 @@ dependencies = [ [[package]] name = "gpu-alloc" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc59e5f710e310e76e6707f86c561dd646f69a8876da9131703b2f717de818d" +checksum = "22beaafc29b38204457ea030f6fb7a84c9e4dd1b86e311ba0542533453d87f62" dependencies = [ "bitflags", "gpu-alloc-types", @@ -1299,7 +1269,7 @@ dependencies = [ "log", "thiserror", "winapi", - "windows", + "windows 0.44.0", ] [[package]] @@ -1310,7 +1280,7 @@ checksum = "0b0c02e1ba0bdb14e965058ca34e09c020f8e507a760df1121728e0aef68d57a" dependencies = [ "bitflags", "gpu-descriptor-types", - "hashbrown", + "hashbrown 0.12.3", ] [[package]] @@ -1334,9 +1304,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66b91535aa35fea1523ad1b86cb6b53c28e0ae566ba4a460f4457e936cad7c6f" +checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" dependencies = [ "bytes", "fnv", @@ -1344,7 +1314,7 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 1.9.3", "slab", "tokio", "tokio-util", @@ -1360,6 +1330,12 @@ dependencies = [ "ahash", ] +[[package]] +name = "hashbrown" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" + [[package]] name = "hassle-rs" version = "0.9.0" @@ -1426,9 +1402,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.25" +version = "0.14.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5e554ff619822309ffd57d8734d77cd5ce6238bc956f037ea06c58238c9899" +checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" dependencies = [ "bytes", "futures-channel", @@ -1463,26 +1439,25 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.53" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765" +checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613" dependencies = [ "android_system_properties", - "core-foundation-sys 0.8.3", + "core-foundation-sys 0.8.4", "iana-time-zone-haiku", "js-sys", "wasm-bindgen", - "winapi", + "windows 0.48.0", ] [[package]] name = "iana-time-zone-haiku" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" dependencies = [ - "cxx", - "cxx-build", + "cc", ] [[package]] @@ -1554,7 +1529,7 @@ dependencies = [ "iced_style", "log", "lyon", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "resvg", "thiserror", ] @@ -1611,7 +1586,7 @@ dependencies = [ "iced_graphics", "iced_native", "log", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "wgpu", "wgpu_glyph", ] @@ -1641,9 +1616,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.3.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -1662,7 +1637,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" dependencies = [ "autocfg", - "hashbrown", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d" +dependencies = [ + "equivalent", + "hashbrown 0.14.0", ] [[package]] @@ -1679,9 +1664,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.7.2" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" +checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" [[package]] name = "ipnetwork" @@ -1734,9 +1719,9 @@ checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] @@ -1749,9 +1734,9 @@ checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" dependencies = [ "wasm-bindgen", ] @@ -1773,16 +1758,16 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", ] [[package]] name = "kurbo" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28a2d0c1781729f69dbea30f968608cadfaeb6582e5ce903a167a5216b53cd0f" +checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", ] [[package]] @@ -1799,9 +1784,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.147" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" [[package]] name = "libloading" @@ -1824,19 +1809,20 @@ dependencies = [ ] [[package]] -name = "libm" -version = "0.2.6" +name = "libloading" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" +checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] [[package]] -name = "link-cplusplus" -version = "1.0.8" +name = "libm" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5" -dependencies = [ - "cc", -] +checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4" [[package]] name = "linked-hash-map" @@ -1846,9 +1832,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" [[package]] name = "lock_api" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" dependencies = [ "autocfg", "scopeguard", @@ -1856,12 +1842,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.17" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] +checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" [[package]] name = "lyon" @@ -1889,7 +1872,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74df1ff0a0147282eb10699537a03baa7d31972b58984a1d44ce0624043fe8ad" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "euclid", "num-traits", ] @@ -1916,10 +1899,10 @@ dependencies = [ ] [[package]] -name = "mach" -version = "0.3.2" +name = "mach2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" +checksum = "6d0d1830bcd151a6fc4aea1369af235b36c1528fe976b8ff678683c9995eade8" dependencies = [ "libc", ] @@ -1971,9 +1954,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" dependencies = [ "autocfg", ] @@ -2013,29 +1996,39 @@ dependencies = [ "adler", ] +[[package]] +name = "miniz_oxide" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +dependencies = [ + "adler", + "simd-adler32", +] + [[package]] name = "mio" -version = "0.8.6" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" +checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", "log", "wasi", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] name = "naga" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eafe22a23b797c9bc227c6c896419b26b5bb88fa903417a3adaed08778850d5" +checksum = "6c3d4269bcb7d50121097702fde1afb75f4ea8083aeb7a55688dcf289a853271" dependencies = [ "bit-set", "bitflags", "codespan-reporting", "hexf-parse", - "indexmap", + "indexmap 1.9.3", "log", "num-traits", "rustc-hash", @@ -2055,7 +2048,7 @@ dependencies = [ "jni-sys", "ndk-sys", "num_enum", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "thiserror", ] @@ -2151,15 +2144,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "nom8" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae01545c9c7fc4486ab7debaf2aad7003ac19431791868fb2e8066df97fad2f8" -dependencies = [ - "memchr", -] - [[package]] name = "num-derive" version = "0.3.3" @@ -2253,9 +2237,9 @@ dependencies = [ [[package]] name = "object" -version = "0.30.3" +version = "0.30.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439" +checksum = "03b4680b86d9cfafba8fc491dc9b6df26b68cf40e9e6cd73909194759a63c385" dependencies = [ "memchr", ] @@ -2285,9 +2269,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.1" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "ordered-float" @@ -2328,7 +2312,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" dependencies = [ - "ttf-parser 0.19.0", + "ttf-parser 0.19.1", ] [[package]] @@ -2373,7 +2357,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.7", + "parking_lot_core 0.9.8", ] [[package]] @@ -2385,22 +2369,22 @@ dependencies = [ "cfg-if", "instant", "libc", - "redox_syscall", + "redox_syscall 0.2.16", "smallvec", "winapi", ] [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.3.5", "smallvec", - "windows-sys 0.45.0", + "windows-targets 0.48.0", ] [[package]] @@ -2426,15 +2410,15 @@ checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" [[package]] name = "percent-encoding" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" +checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" +checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" dependencies = [ "phf_macros", "phf_shared", @@ -2442,9 +2426,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" +checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared", "rand", @@ -2452,22 +2436,22 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" +checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] name = "phf_shared" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" +checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" dependencies = [ "siphasher", ] @@ -2492,15 +2476,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.26" +version = "0.3.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" [[package]] name = "plotters" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +checksum = "d2c224ba00d7cadd4d5c660deaf2098e5e80e07846537c51f9cfa4be50c1fd45" dependencies = [ "num-traits", "plotters-backend", @@ -2510,9 +2494,9 @@ dependencies = [ [[package]] name = "plotters-backend" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" +checksum = "9e76628b4d3a7581389a35d5b6e2139607ad7c75b17aed325f210aa91f4a9609" [[package]] name = "plotters-iced" @@ -2528,14 +2512,15 @@ dependencies = [ [[package]] name = "png" -version = "0.17.7" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d708eaf860a19b19ce538740d2b4bdeeb8337fa53f7738455e706623ad5c638" +checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" dependencies = [ "bitflags", "crc32fast", + "fdeflate", "flate2", - "miniz_oxide", + "miniz_oxide 0.7.1", ] [[package]] @@ -2546,12 +2531,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66618389e4ec1c7afe67d51a9bf34ff9236480f8d51e7489b7d5ab0303c13f34" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ "once_cell", - "toml_edit 0.18.1", + "toml_edit", ] [[package]] @@ -2580,24 +2565,24 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.52" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d0e1ae9e836cc3beddd63db0df682593d7e2d3d891ae8c9083d2113e1744224" +checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb" dependencies = [ "unicode-ident", ] [[package]] name = "profiling" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74605f360ce573babfe43964cbe520294dcb081afbf8c108fc6e23036b4da2df" +checksum = "332cd62e95873ea4f41f3dfd6bbbfc5b52aec892d7e8d534197c4720a0bbbab2" [[package]] name = "quote" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" dependencies = [ "proc-macro2", ] @@ -2659,12 +2644,9 @@ dependencies = [ [[package]] name = "raw-window-handle" -version = "0.5.0" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed7e3d950b66e19e0c372f3fa3fbbcf85b1746b571f74e0c2af6042a5c93420a" -dependencies = [ - "cty", -] +checksum = "f2ff9a1f06a88b01621b7ae906ef0211290d1c8a168a15542486a8f61c0833b9" [[package]] name = "rayon" @@ -2703,6 +2685,15 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.4.3" @@ -2710,15 +2701,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ "getrandom", - "redox_syscall", + "redox_syscall 0.2.16", "thiserror", ] [[package]] name = "regex" -version = "1.7.1" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48aaa5748ba571fb95cd2c85c09f629215d3a6ece942baa100950af03a34f733" +checksum = "d0ab3ca65655bb1e41f2a8c8cd662eb4fb035e67c3f78da1d61dffe89d07300f" dependencies = [ "aho-corasick", "memchr", @@ -2727,9 +2718,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.28" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848" +checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" [[package]] name = "renderdoc-sys" @@ -2879,9 +2870,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.22" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4a36c42d1873f9a77c53bde094f9664d9891bc604a45b4798fd2c389ed12e5b" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] name = "rustc-hash" @@ -2900,9 +2891,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.1" +version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" +checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" dependencies = [ "log", "ring", @@ -2981,12 +2972,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -[[package]] -name = "scratch" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2" - [[package]] name = "sct" version = "0.7.0" @@ -3011,35 +2996,35 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58bc9567378fc7690d6b2addae4e60ac2eeea07becb2c64b9f218b53865cba2a" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.4", + "syn 2.0.22", ] [[package]] name = "serde_json" -version = "1.0.95" +version = "1.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" dependencies = [ "itoa", "ryu", @@ -3048,18 +3033,18 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d" +checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186" dependencies = [ "serde", ] [[package]] name = "serde_test" -version = "1.0.163" +version = "1.0.164" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "100168a8017b89fd4bcbeb8d857d95a8cfcbde829a7147c09cc82d3ab8d8cb41" +checksum = "797c38160e2546a56e1e3439496439597e938669673ffd8af02a12f070da648f" dependencies = [ "serde", ] @@ -3103,6 +3088,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" +[[package]] +name = "simd-adler32" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "238abfbb77c1915110ad968465608b68e869e0772622c9656714e73e5a1a522f" + [[package]] name = "simplecss" version = "0.2.1" @@ -3182,7 +3173,7 @@ dependencies = [ "iced", "iced_lazy", "iced_native", - "indexmap", + "indexmap 2.0.0", "maxminddb", "pcap", "plotters", @@ -3192,7 +3183,7 @@ dependencies = [ "rstest", "serde", "serde_test", - "toml 0.7.4", + "toml 0.7.5", "winres", ] @@ -3252,9 +3243,9 @@ checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" [[package]] name = "strict-num" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9df65f20698aeed245efdde3628a6b559ea1239bbb871af1b6e3b58c413b2bd1" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" dependencies = [ "float-cmp", ] @@ -3297,15 +3288,15 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "98ffacedcdcf1da6579c907279b4f3c5492fbce99fbbf227f5ed270a589c2765" dependencies = [ - "kurbo 0.9.3", + "kurbo 0.9.5", "siphasher", ] [[package]] name = "symphonia" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3671dd6f64f4f9d5c87179525054cfc1f60de23ba1f193bd6ceab812737403f1" +checksum = "62e48dba70095f265fdb269b99619b95d04c89e619538138383e63310b14d941" dependencies = [ "lazy_static", "symphonia-bundle-mp3", @@ -3315,9 +3306,9 @@ dependencies = [ [[package]] name = "symphonia-bundle-mp3" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55a0846e7a2c9a8081ff799fc83a975170417ad2a143f644a77ec2e3e82a2b73" +checksum = "0f31d7fece546f1e6973011a9eceae948133bbd18fd3d52f6073b1e38ae6368a" dependencies = [ "bitflags", "lazy_static", @@ -3328,11 +3319,11 @@ dependencies = [ [[package]] name = "symphonia-core" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9567e2d8a5f866b2f94f5d366d811e0c6826babcff6d37de9e1a6690d38869" +checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bitflags", "bytemuck", "lazy_static", @@ -3341,9 +3332,9 @@ dependencies = [ [[package]] name = "symphonia-metadata" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd35c263223ef6161000be79b124a75de3e065eea563bf3ef169b3e94c7bb2e" +checksum = "89c3e1937e31d0e068bbe829f66b2f2bfaa28d056365279e0ef897172c3320c0" dependencies = [ "encoding_rs", "lazy_static", @@ -3364,9 +3355,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.4" +version = "2.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c622ae390c9302e214c31013517c2061ecb2699935882c60a9b37f82f8625ae" +checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" dependencies = [ "proc-macro2", "quote", @@ -3384,22 +3375,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a9cd18aa97d5c45c6603caea1da6628790b37f7a34b6ca89522331c5180fed0" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.38" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb327af4685e4d03fa8cbcf1716380da910eeb2bb8be417e7f9fd3fb164f36f" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", ] [[package]] @@ -3424,7 +3415,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" dependencies = [ "arrayref", - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bytemuck", "cfg-if", "png", @@ -3469,9 +3460,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.27.0" +version = "1.28.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0de47a4eecbe11f498978a9b29d792f0d2692d1dd003650c24c76510e3bc001" +checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2" dependencies = [ "autocfg", "bytes", @@ -3480,7 +3471,7 @@ dependencies = [ "num_cpus", "pin-project-lite", "socket2 0.4.9", - "windows-sys 0.45.0", + "windows-sys 0.48.0", ] [[package]] @@ -3495,9 +3486,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5427d89453009325de0d8f342c9490009f76e999cb7672d77e46267448f7e6b2" +checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d" dependencies = [ "bytes", "futures-core", @@ -3518,52 +3509,35 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec" +checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" dependencies = [ "serde", "serde_spanned", - "toml_datetime 0.6.2", - "toml_edit 0.19.10", + "toml_datetime", + "toml_edit", ] [[package]] name = "toml_datetime" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4553f467ac8e3d374bc9a177a26801e5d0f9b211aa1673fb137a403afd1c9cf5" - -[[package]] -name = "toml_datetime" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f" +checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.18.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c59d8dd7d0dcbc6428bf7aa2f0e823e26e43b3c9aca15bbc9475d23e5fa12b" -dependencies = [ - "indexmap", - "nom8", - "toml_datetime 0.5.1", -] - -[[package]] -name = "toml_edit" -version = "0.19.10" +version = "0.19.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739" +checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" dependencies = [ - "indexmap", + "indexmap 2.0.0", "serde", "serde_spanned", - "toml_datetime 0.6.2", + "toml_datetime", "winnow", ] @@ -3586,9 +3560,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" +checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" dependencies = [ "once_cell", ] @@ -3607,9 +3581,9 @@ checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" [[package]] name = "ttf-parser" -version = "0.19.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44dcf002ae3b32cd25400d6df128c5babec3927cd1eb7ce813cfff20eb6c3746" +checksum = "a464a4b34948a5f67fddd2b823c62d9d92e44be75058b99939eae6c5b6960b33" [[package]] name = "twox-hash" @@ -3648,9 +3622,9 @@ checksum = "2281c8c1d221438e373249e065ca4989c4c36952c211ff21a0ee91c44a3869e7" [[package]] name = "unicode-ident" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc" +checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" [[package]] name = "unicode-normalization" @@ -3699,9 +3673,9 @@ checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" -version = "2.3.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb" dependencies = [ "form_urlencoded", "idna", @@ -3718,7 +3692,7 @@ dependencies = [ "data-url", "flate2", "imagesize", - "kurbo 0.9.3", + "kurbo 0.9.5", "log", "rctree", "rosvgtree", @@ -3732,7 +3706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "195386e01bc35f860db024de275a76e7a31afdf975d18beb6d0e44764118b4db" dependencies = [ "fontdb", - "kurbo 0.9.3", + "kurbo 0.9.5", "log", "rustybuzz", "unicode-bidi", @@ -3755,22 +3729,20 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -3782,9 +3754,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3792,24 +3764,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.34" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f219e0d211ba40266969f6dbdd90636da12f75bee4fc9d6c23d1260dadb51454" +checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" dependencies = [ "cfg-if", "js-sys", @@ -3819,9 +3791,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3829,22 +3801,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.22", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.84" +version = "0.2.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" +checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" [[package]] name = "wasm-timer" @@ -3936,9 +3908,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.61" +version = "0.3.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" dependencies = [ "js-sys", "wasm-bindgen", @@ -3975,14 +3947,14 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d745a1b6d91d85c33defbb29f0eee0450e1d2614d987e14bf6baf26009d132d7" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "cfg-if", "js-sys", "log", "naga", "parking_lot 0.12.1", "profiling", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "smallvec", "static_assertions", "wasm-bindgen", @@ -3999,7 +3971,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7131408d940e335792645a98f03639573b0480e9e2e7cddbbab74f7c6d9f3fff" dependencies = [ - "arrayvec 0.7.2", + "arrayvec 0.7.4", "bit-vec", "bitflags", "codespan-reporting", @@ -4008,7 +3980,7 @@ dependencies = [ "naga", "parking_lot 0.12.1", "profiling", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "smallvec", "thiserror", "web-sys", @@ -4023,7 +3995,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdcf61a283adc744bb5453dd88ea91f3f86d5ca6b027661c6c73c7734ae0288b" dependencies = [ "android_system_properties", - "arrayvec 0.7.2", + "arrayvec 0.7.4", "ash", "bit-set", "bitflags", @@ -4032,7 +4004,7 @@ dependencies = [ "d3d12", "foreign-types 0.3.2", "fxhash", - "glow 0.12.1", + "glow 0.12.2", "gpu-alloc", "gpu-allocator", "gpu-descriptor", @@ -4048,7 +4020,7 @@ dependencies = [ "parking_lot 0.12.1", "profiling", "range-alloc", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "renderdoc-sys", "smallvec", "thiserror", @@ -4147,7 +4119,25 @@ version = "0.44.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e745dab35a0c4c77aa3ce42d595e13d2003d6902d6b08c9ef5fc326d08da12b" dependencies = [ - "windows-targets 0.42.1", + "windows-targets 0.42.2", +] + +[[package]] +name = "windows" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdacb41e6a96a052c6cb63a144f24900236121c6f63f4f8219fef5977ecb0c25" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", ] [[package]] @@ -4163,15 +4153,6 @@ dependencies = [ "windows_x86_64_msvc 0.36.1", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.1", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -4183,17 +4164,17 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm 0.42.1", - "windows_aarch64_msvc 0.42.1", - "windows_i686_gnu 0.42.1", - "windows_i686_msvc 0.42.1", - "windows_x86_64_gnu 0.42.1", - "windows_x86_64_gnullvm 0.42.1", - "windows_x86_64_msvc 0.42.1", + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", ] [[package]] @@ -4213,9 +4194,9 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" @@ -4231,9 +4212,9 @@ checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" @@ -4249,9 +4230,9 @@ checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" @@ -4267,9 +4248,9 @@ checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" @@ -4285,9 +4266,9 @@ checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" @@ -4297,9 +4278,9 @@ checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" @@ -4315,9 +4296,9 @@ checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" @@ -4347,7 +4328,7 @@ dependencies = [ "parking_lot 0.12.1", "percent-encoding", "raw-window-handle 0.4.3", - "raw-window-handle 0.5.0", + "raw-window-handle 0.5.2", "sctk-adwaita", "smithay-client-toolkit", "wasm-bindgen", diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index a71d2cfe..79a483b8 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -194,7 +194,7 @@ mod tests { PaletteExtension, }; use crate::translations::types::language::Language; - use iced::Color; + use iced::color; use serde::{Deserialize, Serialize}; use serde_test::{assert_tokens, Token}; use std::collections::BTreeMap; @@ -238,68 +238,18 @@ mod tests { ]), palette: CustomPalette { base: Palette { - primary: Color { - r: 30.0 / 255.0, - g: 30.0 / 255.0, - b: 46.0 / 255.0, - a: 1.0, - }, - secondary: Color { - r: 137.0 / 255.0, - g: 180.0 / 255.0, - b: 250.0 / 255.0, - a: 1.0, - }, - buttons: Color { - r: 49.0 / 255.0, - g: 50.0 / 255.0, - b: 68.0 / 255.0, - a: 1.0, - }, - incoming: Color { - r: 137.0 / 255.0, - g: 180.0 / 255.0, - b: 250.0 / 255.0, - a: 1.0, - }, - outgoing: Color { - r: 245.0 / 255.0, - g: 194.0 / 255.0, - b: 231.0 / 255.0, - a: 1.0, - }, - text_headers: Color { - r: 17.0 / 255.0, - g: 17.0 / 255.0, - b: 27.0 / 255.0, - a: 1.0, - }, - text_body: Color { - r: 205.0 / 255.0, - g: 214.0 / 255.0, - b: 244.0 / 255.0, - a: 1.0, - }, - round_borders: Color { - r: 116.0 / 255.0, - g: 199.0 / 255.0, - b: 236.0 / 255.0, - a: 1.0, - }, - round_containers: Color { - r: 88.0 / 255.0, - g: 91.0 / 255.0, - b: 112.0 / 255.0, - a: 1.0, - }, + primary: color!(30, 30, 46), + secondary: color!(137, 180, 250), + buttons: color!(49, 50, 68), + incoming: color!(137, 180, 250), + outgoing: color!(245, 194, 231), + text_headers: color!(17, 17, 27), + text_body: color!(205, 214, 244), + round_borders: color!(116, 199, 236), + round_containers: color!(88, 91, 112), }, extension: PaletteExtension { - starred: Color { - r: 249.0 / 255.0, - g: 226.0 / 255.0, - b: 175.0 / 255.0, - a: 1.0, - }, + starred: color!(249, 226, 175), badge_alpha: 0.75, color_mix_chart: 0.3, }, From 5ad2626d3bfbd09221d4af5e2a14413660e2d0c0 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Tue, 27 Jun 2023 01:52:10 -0400 Subject: [PATCH 09/29] Clean up: Simplify PartialEq impl for Color. --- src/gui/styles/types/color_remote.rs | 47 ++++++---------------------- 1 file changed, 9 insertions(+), 38 deletions(-) diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index 54ba8f2b..8cff1be9 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -17,16 +17,6 @@ const HEX_STR_BASE_LEN: usize = 7; // #aabbccdd is nine bytes long const HEX_STR_ALPHA_LEN: usize = 9; -/// Serde delegate type for [iced::Color]. -// #[derive(Debug, PartialEq, Serialize, Deserialize)] -// #[serde(remote = "iced::Color")] -// pub(super) struct ColorDelegate { -// pub r: f32, -// pub g: f32, -// pub b: f32, -// pub a: f32, -// } - pub(super) fn deserialize_color<'de, D>(deserializer: D) -> Result where D: Deserializer<'de>, @@ -114,27 +104,16 @@ where serializer.serialize_str(&hex_color) } -// Round and truncate [Color] to facilitate comparisons. -pub(super) fn color_round(color: Color) -> Color { - let Color { r, g, b, a } = color; - Color { - r: (r * 1000.0).trunc(), - g: (g * 1000.0).trunc(), - b: (b * 1000.0).trunc(), - a: (a * 1000.0).trunc(), - } -} - -// Lower precision float equality for unit tests and cases where we need Color comparisons. +// Compare [iced::Color] as RGBA. pub(super) fn color_partialeq(color: Color, other: Color) -> bool { - let color = color_round(color); - let other = color_round(other); - color == other + let color = color.into_rgba8(); + let other = other.into_rgba8(); + color.into_iter().eq(other.into_iter()) } #[cfg(test)] mod tests { - use super::{color_partialeq, color_round, deserialize_color, serialize_color}; + use super::{color_partialeq, deserialize_color, serialize_color}; use iced::Color; use serde::{Deserialize, Serialize}; use serde_test::{assert_de_tokens_error, assert_tokens, Token}; @@ -240,9 +219,9 @@ mod tests { ); } - // Test that colors are rounded correctly + // Test color equality #[test] - fn test_color_rounding() { + fn test_color_partialeq() { let color = Color { r: 1.0 / 3.0, g: 2.0 / 3.0, @@ -250,15 +229,7 @@ mod tests { #[allow(clippy::excessive_precision)] a: 1.618033988749, }; - - let color_rounded = color_round(color); - let color_expected = Color { - r: 333.0, - g: 666.0, - b: 1000.0, - a: 1618.0, - }; - - assert_eq!(color_expected, color_rounded); + let other = color; + assert!(color_partialeq(color, other)) } } From d35c578585dd2ac77132658b55e0f18f34251e71 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Tue, 27 Jun 2023 23:35:55 -0400 Subject: [PATCH 10/29] Clean up: Derive PartialEq instead of implementing I previously wrote PartialEq implementations for `Color` and structs that used it, but deriving it seems to work fine now. --- src/gui/styles/types/color_remote.rs | 31 ++------------ src/gui/styles/types/custom_style.rs | 61 +--------------------------- 2 files changed, 5 insertions(+), 87 deletions(-) diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index 8cff1be9..5380da68 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -104,16 +104,10 @@ where serializer.serialize_str(&hex_color) } -// Compare [iced::Color] as RGBA. -pub(super) fn color_partialeq(color: Color, other: Color) -> bool { - let color = color.into_rgba8(); - let other = other.into_rgba8(); - color.into_iter().eq(other.into_iter()) -} #[cfg(test)] mod tests { - use super::{color_partialeq, deserialize_color, serialize_color}; + use super::{deserialize_color, serialize_color}; use iced::Color; use serde::{Deserialize, Serialize}; use serde_test::{assert_de_tokens_error, assert_tokens, Token}; @@ -135,7 +129,7 @@ mod tests { a: 128.0 / 255.0, }; - #[derive(Debug, Deserialize, Serialize)] + #[derive(Debug, PartialEq, Deserialize, Serialize)] #[serde(transparent)] struct DelegateTest { #[serde( @@ -146,12 +140,6 @@ mod tests { color: Color, } - impl PartialEq for DelegateTest { - fn eq(&self, other: &Self) -> bool { - color_partialeq(self.color, other.color) - } - } - const CATPPUCCIN_PINK_DELEGATE: DelegateTest = DelegateTest { color: CATPPUCCIN_PINK, }; @@ -202,6 +190,7 @@ mod tests { ); } + // A hex string that is too long shouldn't deserialize #[test] fn test_len_too_large_color_de() { assert_de_tokens_error::( @@ -218,18 +207,4 @@ mod tests { "invalid value: string \"#ca🐈\", expected valid hexadecimal", ); } - - // Test color equality - #[test] - fn test_color_partialeq() { - let color = Color { - r: 1.0 / 3.0, - g: 2.0 / 3.0, - b: 3.0 / 3.0, - #[allow(clippy::excessive_precision)] - a: 1.618033988749, - }; - let other = color; - assert!(color_partialeq(color, other)) - } } diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 79a483b8..30e9af52 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -35,10 +35,7 @@ use std::{ io::{BufReader, Read}, }; -use super::{ - color_remote::color_partialeq, - palette::{Palette, PaletteExtension}, -}; +use super::palette::{Palette, PaletteExtension}; use crate::Language; /// Custom color scheme data including the palette, name, and location of the toml. @@ -99,7 +96,7 @@ impl CustomStyle { // Clippy complains about deriving [Hash] with a manually written [PartialEq]. We manually implemented // Hash for [Palette] and [PaletteExtension], so deriving Hash is convenient and the error is spurious. #[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Debug, Hash, Clone, Deserialize, Serialize)] +#[derive(Debug, Hash, Clone, PartialEq, Deserialize, Serialize)] pub struct CustomPalette { /// Base colors as used for the default sniffnet themes. #[serde(flatten)] @@ -109,60 +106,6 @@ pub struct CustomPalette { pub extension: PaletteExtension, } -impl PartialEq for CustomPalette { - fn eq(&self, other: &Self) -> bool { - let Palette { - primary, - secondary, - buttons, - incoming, - outgoing, - text_headers, - text_body, - round_borders, - round_containers, - } = self.base; - - let PaletteExtension { - starred, - badge_alpha, - color_mix_chart, - } = self.extension; - - // Other - let Palette { - primary: primary_other, - secondary: secondary_other, - buttons: buttons_other, - incoming: incoming_other, - outgoing: outgoing_other, - text_headers: text_headers_other, - text_body: text_body_other, - round_borders: round_borders_other, - round_containers: round_containers_other, - } = other.base; - - let PaletteExtension { - starred: starred_other, - badge_alpha: badge_alpha_other, - color_mix_chart: color_mix_chart_other, - } = other.extension; - - color_partialeq(primary, primary_other) - && color_partialeq(secondary, secondary_other) - && color_partialeq(buttons, buttons_other) - && color_partialeq(incoming, incoming_other) - && color_partialeq(outgoing, outgoing_other) - && color_partialeq(text_headers, text_headers_other) - && color_partialeq(text_body, text_body_other) - && color_partialeq(round_borders, round_borders_other) - && color_partialeq(round_containers, round_containers_other) - && color_partialeq(starred, starred_other) - && badge_alpha == badge_alpha_other - && color_mix_chart == color_mix_chart_other - } -} - /// Deserialize [CustomStyle] from a file path. /// /// This is implemented by first deserializing a file path which in turn contains the style as TOML. From cc1db3e72cfee7bb76305424f1a12863c8fb23d1 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Fri, 30 Jun 2023 00:42:02 -0400 Subject: [PATCH 11/29] Fix serializing `StyleType::Custom`. `StyleType` should serialize as a TOML table to account for `StyleType::Custom` taking a value. I added two attributes to `StyleType` to hint that the `toml` crate should serialize it as a table instead of a simple key = value. --- src/configs/types/config_settings.rs | 3 +- src/gui/styles/types/custom_style.rs | 48 ++++++++++++++++++++++++++-- src/gui/styles/types/style_type.rs | 1 + 3 files changed, 49 insertions(+), 3 deletions(-) diff --git a/src/configs/types/config_settings.rs b/src/configs/types/config_settings.rs index 22aef7f5..0f05c115 100644 --- a/src/configs/types/config_settings.rs +++ b/src/configs/types/config_settings.rs @@ -10,7 +10,8 @@ use crate::{Language, StyleType}; #[derive(Serialize, Deserialize, Default)] pub struct ConfigSettings { - pub style: Arc, pub language: Language, pub notifications: Notifications, + // This field should be last so that the TOML for StyleType can serialize properly + pub style: Arc, } diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 30e9af52..54f995a0 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -136,7 +136,7 @@ mod tests { deserialize_from_path, serialize_to_path, CustomPalette, CustomStyle, Palette, PaletteExtension, }; - use crate::translations::types::language::Language; + use crate::{translations::types::language::Language, StyleType}; use iced::color; use serde::{Deserialize, Serialize}; use serde_test::{assert_tokens, Token}; @@ -200,11 +200,55 @@ mod tests { }) } + // Test that split deserialization works for `CustomStyle`. + // This is different than testing that `StyleType` properly deserializes. #[test] - fn test_styletype_split_de() { + fn test_customstyle_split_de() { let style_test = catppuccin_style(); // This is only used for the test which requires an &'static str. let path: &'static str = Box::leak(style_path().into_boxed_str()); assert_tokens(&style_test, &[Token::String(path)]); } + + // Ensure that StyleType itself still deserializes properly + #[test] + fn test_styletype_unit_split_de() { + // Unit variant without a struct + assert_tokens( + &StyleType::DeepSea, + &[ + Token::Struct { + name: "StyleType", + len: 1, + }, + Token::Str("style"), + Token::Str("DeepSea"), + Token::StructEnd, + ], + ); + } + + // Test that StyleType::Custom successfully deserializes. + // Originally, StyleType::Custom did not ser/de correctly because of how TOML + // handles enums. + #[test] + fn test_styletype_custom_split_de() { + // CustomStyle + // This is only used for the test so leaking it is fine. + let path = &*Box::leak(style_path().into_boxed_str()); + assert_tokens( + &StyleType::Custom(catppuccin_style().0), + &[ + Token::Struct { + name: "StyleType", + len: 2, + }, + Token::Str("style"), + Token::Str("Custom"), + Token::Str("path"), + Token::Str(path), + Token::StructEnd, + ], + ); + } } diff --git a/src/gui/styles/types/style_type.rs b/src/gui/styles/types/style_type.rs index c94d9621..89640b9f 100644 --- a/src/gui/styles/types/style_type.rs +++ b/src/gui/styles/types/style_type.rs @@ -4,6 +4,7 @@ use super::custom_style::{deserialize_from_path, serialize_to_path, CustomStyle} /// Used to specify the kind of style of the application #[derive(Clone, Serialize, Deserialize, Debug, Hash, PartialEq)] +#[serde(tag = "style", content = "path")] pub enum StyleType { Night, Day, From 94fea30b5c4454d70696b0d363c270d4d7fe6dad Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Mon, 3 Jul 2023 01:16:58 -0400 Subject: [PATCH 12/29] Handle `CustomStyle` translations better. --- src/gui/pages/settings_style_page.rs | 4 +-- src/gui/styles/types/custom_style.rs | 39 ++++++++++++++++++++++++++-- src/translations/translations.rs | 8 ++++++ 3 files changed, 47 insertions(+), 4 deletions(-) diff --git a/src/gui/pages/settings_style_page.rs b/src/gui/pages/settings_style_page.rs index 7fd37ee1..cfd8f6fd 100644 --- a/src/gui/pages/settings_style_page.rs +++ b/src/gui/pages/settings_style_page.rs @@ -17,7 +17,7 @@ use crate::gui::styles::types::element_type::ElementType; use crate::gui::styles::types::style_tuple::StyleTuple; use crate::gui::types::message::Message; use crate::translations::translations::{ - appearance_title_translation, deep_sea_translation, mon_amour_translation, + appearance_title_translation, custom_theme_path, deep_sea_translation, mon_amour_translation, yeti_day_translation, yeti_night_translation, }; use crate::StyleType::{Day, DeepSea, MonAmour, Night}; @@ -93,7 +93,7 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { .push( Row::new().push( TextInput::new( - "Path to custom theme and hit enter!", + custom_theme_path(sniffer.language), sniffer.style_path_update.as_deref().unwrap_or_default(), ) .font(font) diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 54f995a0..2a7592d4 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -31,8 +31,9 @@ use serde::{de::Error as DeErrorTrait, Deserialize, Deserializer, Serialize, Serializer}; use std::{ collections::BTreeMap, - fs::File, - io::{BufReader, Read}, + fs::{self, File}, + io::{self, BufReader, Read}, + path::{Path, PathBuf}, }; use super::palette::{Palette, PaletteExtension}; @@ -85,6 +86,40 @@ impl CustomStyle { style }) } + + /// Load [CustomStyle]s from a directory. + /// + /// # Errors + /// [io::Error] is only returned if `dir` can't be read. A best effort is made to read any styles + /// present in the directory. + pub fn from_dir

(dir: P) -> Result, io::Error> + where + P: Into, + { + let iter = fs::read_dir(dir.into())?.filter_map(|entry| { + let entry = entry.ok()?.path(); + Self::from_file(entry.to_str()?).ok() + }); + Ok(iter) + } + + /// Return translated description or a default. + /// + /// Defaults to English is the language isn't implemented or "" if English is missing too. + /// + /// # Arguments + /// * `language` - Description language + pub fn description(&self, language: Language) -> &str { + self.description + .get(&language) + .map(|s| s.as_str()) + .unwrap_or_else(|| { + self.description + .get(&Language::EN) + .map(|s| s.as_str()) + .unwrap_or_default() + }) + } } /// Base [Palette] and extension colors for [CustomStyle]. diff --git a/src/translations/translations.rs b/src/translations/translations.rs index cece8d1e..76bd1f84 100644 --- a/src/translations/translations.rs +++ b/src/translations/translations.rs @@ -1714,3 +1714,11 @@ pub fn only_last_30_translation(language: Language) -> &'static str { Language::SV => "Endast de senaste 30 notifikationerna visas", } } + +pub fn custom_theme_path(language: Language) -> &'static str { + // Currently only English because it's a new text + match language { + Language::EN => "Path to a custom theme and hit enter!", + _ => custom_theme_path(Language::EN), + } +} From 56c7f70a9c9f87fe5b1776832e308ee4d6d62b1f Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Sun, 9 Jul 2023 00:41:08 -0400 Subject: [PATCH 13/29] Impl `get_custom_styles` to load styles from a dir --- src/gui/pages/settings_style_page.rs | 69 ++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 5 deletions(-) diff --git a/src/gui/pages/settings_style_page.rs b/src/gui/pages/settings_style_page.rs index a9db6869..32308990 100644 --- a/src/gui/pages/settings_style_page.rs +++ b/src/gui/pages/settings_style_page.rs @@ -1,16 +1,15 @@ use std::sync::Arc; use iced::alignment::{Horizontal, Vertical}; -use iced::widget::{Button, Column, Container, Row, Text}; +use iced::widget::{Button, Column, Container, Row, Space, Text, TextInput}; use iced::{Alignment, Length}; use iced_native::widget::{horizontal_space, vertical_space, Rule}; -use iced::widget::TextInput; - use crate::gui::components::tab::get_settings_tabs; use crate::gui::pages::settings_notifications_page::settings_header; use crate::gui::pages::types::settings_page::SettingsPage; use crate::gui::styles::style_constants::{get_font, BORDER_WIDTH, FONT_SIZE_SUBTITLE}; +use crate::gui::styles::types::custom_style::CustomStyle; use crate::gui::styles::types::element_type::ElementType; use crate::gui::styles::types::style_tuple::StyleTuple; use crate::gui::types::message::Message; @@ -18,12 +17,13 @@ use crate::translations::translations::{ appearance_title_translation, custom_theme_path, deep_sea_translation, mon_amour_translation, yeti_day_translation, yeti_night_translation, }; +use crate::translations::types::language::Language; use crate::StyleType::{Day, DeepSea, MonAmour, Night}; use crate::{Sniffer, StyleType}; pub fn settings_style_page(sniffer: &Sniffer) -> Container { let font = get_font(&sniffer.style); - let content = Column::new() + let mut content = Column::new() .align_items(Alignment::Center) .width(Length::Fill) .push(settings_header(&sniffer.style, sniffer.language)) @@ -82,8 +82,17 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { mon_amour_translation(sniffer.language).to_string(), &Arc::new(MonAmour), )), - ) + ); + + // Append custom style buttons if any exist + if let Some(custom_styles) = get_custom_styles(sniffer.language) { + content = content.push(custom_styles); + } + + // Append text box to manually load custom styles from a TOML file + let content = content .push(vertical_space(Length::Fixed(10.0))) + // Custom theme text box .push( Row::new().push( TextInput::new( @@ -177,3 +186,53 @@ fn get_palette(style: &Arc) -> Container<'static, Message> { StyleTuple(Arc::clone(style), ElementType::Palette), )) } + +// Load and process `CustomStyles`. +fn get_custom_styles(lang: Language) -> Option> { + let mut styles = confy::get_configuration_file_path("sniffnet", None) + .ok() + .and_then(|mut path| { + path.push("themes"); + CustomStyle::from_dir(path).ok() + })? + .map(|style| { + let name = style.name.clone(); + let description = style.description(lang).to_owned(); + let style = Arc::new(StyleType::Custom(style)); + get_palette_container(&style, name, description, &style) + }); + + // The easiest way to do this is with itertools, but I don't want to introduce another + // dependency just for this one function. So I'll do it iteratively for now. + let mut children = if let (_, Some(capacity)) = styles.size_hint() { + Vec::with_capacity(capacity) + } else { + Vec::new() + }; + + // This handles the case where there aren't an even number of styles. + // [Iterator::zip] drops remainders. Itertools' `zip_longest` and the unstable array chunks API + // are both better solutions. + while let (Some(first), second) = (styles.next(), styles.next()) { + // Add both styles and the vertical space to a row if there are two styles. + if let Some(second) = second { + children.extend([ + Row::new() + .push(first) + .push(horizontal_space(Length::Fixed(15.0))) + .push(second) + .into(), + >>::into(vertical_space(Length::Fixed(10.0))), + ]); + } + // Or else just add the single style and the space + else { + children.extend([ + Row::new().push(first).into(), + >>::into(vertical_space(Length::Fixed(10.0))), + ]); + } + } + + Some(Column::with_children(children)) +} From ec863ea0fdf520960cf684eb0df0833cb9d91b59 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Sun, 9 Jul 2023 21:22:47 -0400 Subject: [PATCH 14/29] Make the settings style page scrollable. --- src/gui/pages/settings_style_page.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/gui/pages/settings_style_page.rs b/src/gui/pages/settings_style_page.rs index 32308990..c10c40b9 100644 --- a/src/gui/pages/settings_style_page.rs +++ b/src/gui/pages/settings_style_page.rs @@ -1,8 +1,8 @@ use std::sync::Arc; use iced::alignment::{Horizontal, Vertical}; -use iced::widget::{Button, Column, Container, Row, Space, Text, TextInput}; -use iced::{Alignment, Length}; +use iced::widget::{Button, Column, Container, Row, Scrollable, Space, Text, TextInput}; +use iced::{Alignment, Element, Length}; use iced_native::widget::{horizontal_space, vertical_space, Rule}; use crate::gui::components::tab::get_settings_tabs; @@ -86,11 +86,14 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { // Append custom style buttons if any exist if let Some(custom_styles) = get_custom_styles(sniffer.language) { - content = content.push(custom_styles); + content = content.push(vertical_space(Length::Fixed(10.0))); + for child in custom_styles { + content = content.push(child); + } } // Append text box to manually load custom styles from a TOML file - let content = content + content = content .push(vertical_space(Length::Fixed(10.0))) // Custom theme text box .push( @@ -112,6 +115,9 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { ), ); + // Wrap content into a scrollable widget + let content = Scrollable::new(content); + Container::new(content) .height(Length::Fixed(440.0)) .width(Length::Fixed(800.0)) @@ -188,10 +194,12 @@ fn get_palette(style: &Arc) -> Container<'static, Message> { } // Load and process `CustomStyles`. -fn get_custom_styles(lang: Language) -> Option> { +fn get_custom_styles(lang: Language) -> Option>> { + // Lazily load `CustomStyles` and process them into GUI elements. let mut styles = confy::get_configuration_file_path("sniffnet", None) .ok() .and_then(|mut path| { + path.pop(); path.push("themes"); CustomStyle::from_dir(path).ok() })? @@ -234,5 +242,5 @@ fn get_custom_styles(lang: Language) -> Option> { } } - Some(Column::with_children(children)) + Some(children) } From 04b790afe050fc1f986da6ba97ab56526cc0735a Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Mon, 10 Jul 2023 23:00:00 -0400 Subject: [PATCH 15/29] Add and update Catppuccin styles. --- resources/themes/catppuccin_frappe.toml | 20 ++++++++++++++++++++ resources/themes/catppuccin_latte.toml | 22 ++++++++++++++++++++++ resources/themes/catppuccin_macchiato.toml | 20 ++++++++++++++++++++ resources/themes/catppuccin_mocha.toml | 9 +++++---- src/gui/styles/types/custom_style.rs | 8 ++++---- 5 files changed, 71 insertions(+), 8 deletions(-) create mode 100644 resources/themes/catppuccin_frappe.toml create mode 100644 resources/themes/catppuccin_latte.toml create mode 100644 resources/themes/catppuccin_macchiato.toml diff --git a/resources/themes/catppuccin_frappe.toml b/resources/themes/catppuccin_frappe.toml new file mode 100644 index 00000000..ec903cb3 --- /dev/null +++ b/resources/themes/catppuccin_frappe.toml @@ -0,0 +1,20 @@ +# https://github.com/catppuccin/catppuccin +name = "Catppuccin (Frappé)" + +[description] +EN = "Soothing pastel theme for the high-spirited!" +# Contributed by Bartosz +PL = "Kojący pastelowy motyw dla porywczych" + +[palette] +primary = "#303446" # Base +secondary = "#8caaee" # Blue +buttons = "#414559" # Surface0 +outgoing = "#f4b8e4" # Pink +text_headers = "#232634" # Crust +text_body = "#c6d0f5" # Text +round_borders = "#babbf1" # Lavender +round_containers = "#292c3c" # Mantle +starred = "#e5c890" # Yellow +badge_alpha = 0.75 +color_mix_chart = 0.3 diff --git a/resources/themes/catppuccin_latte.toml b/resources/themes/catppuccin_latte.toml new file mode 100644 index 00000000..6e18e999 --- /dev/null +++ b/resources/themes/catppuccin_latte.toml @@ -0,0 +1,22 @@ +# https://github.com/catppuccin/catppuccin +name = "Catppuccin (Latte)" + +[description] +EN = "Soothing pastel theme for the high-spirited!" +# Contributed by Emilia +# HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" +# Contributed by Bartosz +PL = "Kojący pastelowy motyw dla porywczych" + +[palette] +primary = "#eff1f5" # Base +secondary = "#1e66f5" # Blue +buttons = "#ccd0da" # Surface0 +outgoing = "#ea76cb" # Pink +text_headers = "#dce0e8" # Crust +text_body = "#4c4f69" # Text +round_borders = "#7287fd" # Lavender +round_containers = "#e6e9ef" # Mantle +starred = "#df8e1d" # Yellow +badge_alpha = 0.75 +color_mix_chart = 0.3 diff --git a/resources/themes/catppuccin_macchiato.toml b/resources/themes/catppuccin_macchiato.toml new file mode 100644 index 00000000..fd433b3d --- /dev/null +++ b/resources/themes/catppuccin_macchiato.toml @@ -0,0 +1,20 @@ +# https://github.com/catppuccin/catppuccin +name = "Catppuccin (Macchiato)" + +[description] +EN = "Soothing pastel theme for the high-spirited!" +# Contributed by Bartosz +PL = "Kojący pastelowy motyw dla porywczych" + +[palette] +primary = "#24273a" # Base +secondary = "#8aadf4" # Blue +buttons = "#363a4f" # Surface0 +outgoing = "#f5bde6" # Pink +text_headers = "#181926" # Crust +text_body = "#cad3f5" # Text +round_borders = "#b7bdf8" # Lavender +round_containers = "#1e2030" # Mantle +starred = "#eed49f" # Yellow +badge_alpha = 0.75 +color_mix_chart = 0.3 diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index 94222153..20f5639d 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -1,11 +1,12 @@ +# https://github.com/catppuccin/catppuccin name = "Catppuccin (Mocha)" [description] -EN = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin" +EN = "Soothing pastel theme for the high-spirited!" # Contributed by Emilia # HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" # Contributed by Bartosz -PL = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin" +PL = "Kojący pastelowy motyw dla porywczych" [palette] primary = "#1e1e2e" # Base @@ -14,8 +15,8 @@ buttons = "#313244" # Surface0 outgoing = "#f5c2e7" # Pink text_headers = "#11111b" # Crust text_body = "#cdd6f4" # Text -round_borders = "#74c7ec" # Sapphire -round_containers = "#585b70" # Surface 2 +round_borders = "#b4befe" # Lavender +round_containers = "#181825" # Mantle starred = "#f9e2af" # Yellow badge_alpha = 0.75 color_mix_chart = 0.3 diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 7180c64f..62df814c 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -197,11 +197,11 @@ mod tests { ) } - const STYLE_DESC_ENG: &str = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin"; + const STYLE_DESC_ENG: &str = "Soothing pastel theme for the high-spirited!"; // Hungarian translation by Emi. const STYLE_DESC_HU: &str = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin"; // Polish translation by Bartosz. - const STYLE_DESC_PL: &str = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin"; + const STYLE_DESC_PL: &str = "Kojący pastelowy motyw dla porywczych"; // NOTE: This has to be updated if `resources/themes/catppuccin_mocha.toml` changes fn catppuccin_style() -> StyleForTests { @@ -221,8 +221,8 @@ mod tests { outgoing: color!(245, 194, 231), text_headers: color!(17, 17, 27), text_body: color!(205, 214, 244), - round_borders: color!(116, 199, 236), - round_containers: color!(88, 91, 112), + round_borders: color!(180, 190, 254), + round_containers: color!(24, 24, 37), }, extension: PaletteExtension { starred: color!(249, 226, 175), From 773de55421f401dfa552b393e44db1482f33a662 Mon Sep 17 00:00:00 2001 From: Joshua Megnauth Date: Tue, 11 Jul 2023 01:36:18 -0400 Subject: [PATCH 16/29] Add unit test for `load_custom_styles` This adds a unit test to ensure that every built in custom theme successfully deserializes. --- Cargo.lock | 205 ++++++++++++++------------- Cargo.toml | 6 +- src/gui/pages/settings_style_page.rs | 56 ++++++-- 3 files changed, 154 insertions(+), 113 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24ea2bcb..f98f81ed 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,9 +125,9 @@ checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" [[package]] name = "ash" @@ -235,7 +235,7 @@ checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", ] [[package]] @@ -485,12 +485,13 @@ dependencies = [ [[package]] name = "core-graphics-types" -version = "0.1.2" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bb142d41022986c1d8ff29103a1411c8a3dfad3552f87a4f8dc50d61d4f4e33" +checksum = "3a68b68b3446082644c91ac778bf50cd4104bfb002b5a6a7c44cca5a2c70788b" dependencies = [ "bitflags", "core-foundation", + "foreign-types 0.3.2", "libc", ] @@ -583,22 +584,22 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.15" +version = "0.9.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae211234986c545741a7dc064309f67ee1e5ad243d0e48335adc0484d960bcc7" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" dependencies = [ "autocfg", "cfg-if", "crossbeam-utils", - "memoffset 0.9.0", + "memoffset 0.8.0", "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" dependencies = [ "cfg-if", ] @@ -847,7 +848,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "827292ea592108849932ad8e30218f8b1f21c0dfd0696698a18b5d0aed62d990" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", ] [[package]] @@ -966,7 +967,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", ] [[package]] @@ -1069,7 +1070,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", ] [[package]] @@ -1150,9 +1151,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.27.3" +version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" +checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" [[package]] name = "glam" @@ -1304,9 +1305,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.20" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049" +checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782" dependencies = [ "bytes", "fnv", @@ -1402,9 +1403,9 @@ checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" [[package]] name = "hyper" -version = "0.14.27" +version = "0.14.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468" +checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4" dependencies = [ "bytes", "futures-channel", @@ -1664,9 +1665,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.8.0" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6" +checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f" [[package]] name = "ipnetwork" @@ -1734,9 +1735,9 @@ checksum = "bc0000e42512c92e31c2252315bda326620a4e034105e900c98ec492fa077b3e" [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" dependencies = [ "wasm-bindgen", ] @@ -1758,7 +1759,7 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a53776d271cfb873b17c618af0298445c88afc52837f3e948fa3fafd131f449" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", ] [[package]] @@ -1767,7 +1768,7 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd85a5776cd9500c2e2059c8c76c3b01528566b7fcbaf8098b55a33fc298849b" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", ] [[package]] @@ -1784,9 +1785,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" [[package]] name = "libloading" @@ -1842,9 +1843,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.19" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" [[package]] name = "lyon" @@ -1872,7 +1873,7 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74df1ff0a0147282eb10699537a03baa7d31972b58984a1d44ce0624043fe8ad" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", "euclid", "num-traits", ] @@ -1954,9 +1955,9 @@ dependencies = [ [[package]] name = "memoffset" -version = "0.9.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" dependencies = [ "autocfg", ] @@ -2312,7 +2313,7 @@ version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "706de7e2214113d63a8238d1910463cfce781129a6f263d13fdb09ff64355ba4" dependencies = [ - "ttf-parser 0.19.1", + "ttf-parser 0.19.0", ] [[package]] @@ -2416,9 +2417,9 @@ checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" [[package]] name = "phf" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ade2d8b8f33c7333b51bcf0428d37e217e9f32192ae4772156f65063b8ce03dc" +checksum = "928c6535de93548188ef63bb7c4036bd415cd8f36ad25af44b9789b2ee72a48c" dependencies = [ "phf_macros", "phf_shared", @@ -2426,9 +2427,9 @@ dependencies = [ [[package]] name = "phf_generator" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" +checksum = "b1181c94580fa345f50f19d738aaa39c0ed30a600d95cb2d3e23f94266f14fbf" dependencies = [ "phf_shared", "rand", @@ -2436,22 +2437,22 @@ dependencies = [ [[package]] name = "phf_macros" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3444646e286606587e49f3bcf1679b8cef1dc2c5ecc29ddacaffc305180d464b" +checksum = "92aacdc5f16768709a569e913f7451034034178b05bdc8acda226659a3dccc66" dependencies = [ "phf_generator", "phf_shared", "proc-macro2", "quote", - "syn 2.0.22", + "syn 1.0.109", ] [[package]] name = "phf_shared" -version = "0.11.2" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90fcb95eef784c2ac79119d1dd819e162b5da872ce6f3c3abe1e8ca1c082f72b" +checksum = "e1fb5f6f826b772a8d4c0394209441e7d37cbbb967ae9c7e0e8134365c9ee676" dependencies = [ "siphasher", ] @@ -2512,9 +2513,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.9" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59871cc5b6cce7eaccca5a802b4173377a1c2ba90654246789a8fa2334426d11" +checksum = "aaeebc51f9e7d2c150d3f3bfeb667f2aa985db5ef1e3d212847bdedb488beeaa" dependencies = [ "bitflags", "crc32fast", @@ -2722,6 +2723,12 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78" +[[package]] +name = "relative-path" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf2521270932c3c7bed1a59151222bd7643c79310f2916f01925e1e16255698" + [[package]] name = "renderdoc-sys" version = "0.7.1" @@ -2844,9 +2851,9 @@ dependencies = [ [[package]] name = "rstest" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de1bb486a691878cd320c2f0d319ba91eeaa2e894066d8b5f8f117c000e9d962" +checksum = "2b96577ca10cb3eade7b337eb46520108a67ca2818a24d0b63f41fd62bc9651c" dependencies = [ "futures", "futures-timer", @@ -2856,15 +2863,18 @@ dependencies = [ [[package]] name = "rstest_macros" -version = "0.17.0" +version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290ca1a1c8ca7edb7c3283bd44dc35dd54fdec6253a3912e201ba1072018fca8" +checksum = "225e674cf31712b8bb15fdbca3ec0c1b9d825c5a24407ff2b7e005fb6a29ba03" dependencies = [ "cfg-if", + "glob", "proc-macro2", "quote", + "regex", + "relative-path", "rustc_version", - "syn 1.0.109", + "syn 2.0.25", "unicode-ident", ] @@ -2891,9 +2901,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.2" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e32ca28af694bc1bbf399c33a516dbdf1c90090b8ab23c2bc24f834aa2247f5f" +checksum = "c911ba11bc8433e811ce56fde130ccf32f5127cab0e0194e9c68c5a5b671791e" dependencies = [ "log", "ring", @@ -3002,29 +3012,29 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" [[package]] name = "serde" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8c8cf938e98f769bc164923b06dce91cea1751522f46f8466461af04c9027d" +checksum = "30e27d1e4fd7659406c492fd6cfaf2066ba8773de45ca75e855590f856dc34a9" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9735b638ccc51c28bf6914d90a2e9725b377144fc612c49a611fddd1b631d68" +checksum = "389894603bd18c46fa56231694f8d827779c0951a667087194cf9de94ed24682" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", ] [[package]] name = "serde_json" -version = "1.0.99" +version = "1.0.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46266871c240a00b8f503b877622fe33430b3c7d963bdc0f2adc511e54a1eae3" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" dependencies = [ "itoa", "ryu", @@ -3042,9 +3052,9 @@ dependencies = [ [[package]] name = "serde_test" -version = "1.0.164" +version = "1.0.171" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "797c38160e2546a56e1e3439496439597e938669673ffd8af02a12f070da648f" +checksum = "b6480a2f4e1449ec9757ea143362ad5cea79bc7f1cb7711c06e1c5d03b6b5a3a" dependencies = [ "serde", ] @@ -3183,7 +3193,7 @@ dependencies = [ "rstest", "serde", "serde_test", - "toml 0.7.5", + "toml 0.7.6", "winres", ] @@ -3323,7 +3333,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7c73eb88fee79705268cc7b742c7bc93a7b76e092ab751d0833866970754142" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", "bitflags", "bytemuck", "lazy_static", @@ -3355,9 +3365,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.22" +version = "2.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efbeae7acf4eabd6bcdcbd11c92f45231ddda7539edc7806bd1a04a03b24616" +checksum = "15e3fc8c0c74267e2df136e5e5fb656a464158aa57624053375eb9c8c6e25ae2" dependencies = [ "proc-macro2", "quote", @@ -3390,7 +3400,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", ] [[package]] @@ -3415,7 +3425,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df8493a203431061e901613751931f047d1971337153f96d0e5e363d6dbf6a67" dependencies = [ "arrayref", - "arrayvec 0.7.4", + "arrayvec 0.7.2", "bytemuck", "cfg-if", "png", @@ -3476,9 +3486,9 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.24.1" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +checksum = "e0d409377ff5b1e3ca6437aa86c1eb7d40c134bfec254e44c830defa92669db5" dependencies = [ "rustls", "tokio", @@ -3509,9 +3519,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebafdf5ad1220cb59e7d17cf4d2c72015297b75b19a10472f99b89225089240" +checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542" dependencies = [ "serde", "serde_spanned", @@ -3530,9 +3540,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.19.11" +version = "0.19.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "266f016b7f039eec8a1a80dfe6156b633d208b9fccca5e4db1d6775b0c4e34a7" +checksum = "c500344a19072298cd05a7224b3c0c629348b78692bf48466c5238656e315a78" dependencies = [ "indexmap 2.0.0", "serde", @@ -3581,9 +3591,9 @@ checksum = "0609f771ad9c6155384897e1df4d948e692667cc0588548b68eb44d052b27633" [[package]] name = "ttf-parser" -version = "0.19.1" +version = "0.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a464a4b34948a5f67fddd2b823c62d9d92e44be75058b99939eae6c5b6960b33" +checksum = "44dcf002ae3b32cd25400d6df128c5babec3927cd1eb7ce813cfff20eb6c3746" [[package]] name = "twox-hash" @@ -3739,10 +3749,11 @@ dependencies = [ [[package]] name = "want" -version = "0.3.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ + "log", "try-lock", ] @@ -3754,9 +3765,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -3764,24 +3775,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.37" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03" +checksum = "2d1985d03709c53167ce907ff394f5316aa22cb4e12761295c5dc57dacb6297e" dependencies = [ "cfg-if", "js-sys", @@ -3791,9 +3802,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3801,22 +3812,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.22", + "syn 2.0.25", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" [[package]] name = "wasm-timer" @@ -3908,9 +3919,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.64" +version = "0.3.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b" +checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2" dependencies = [ "js-sys", "wasm-bindgen", @@ -3947,7 +3958,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d745a1b6d91d85c33defbb29f0eee0450e1d2614d987e14bf6baf26009d132d7" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", "cfg-if", "js-sys", "log", @@ -3971,7 +3982,7 @@ version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7131408d940e335792645a98f03639573b0480e9e2e7cddbbab74f7c6d9f3fff" dependencies = [ - "arrayvec 0.7.4", + "arrayvec 0.7.2", "bit-vec", "bitflags", "codespan-reporting", @@ -3995,7 +4006,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bdcf61a283adc744bb5453dd88ea91f3f86d5ca6b027661c6c73c7734ae0288b" dependencies = [ "android_system_properties", - "arrayvec 0.7.4", + "arrayvec 0.7.2", "ash", "bit-set", "bitflags", @@ -4341,9 +4352,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.4.7" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448" +checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699" dependencies = [ "memchr", ] diff --git a/Cargo.toml b/Cargo.toml index 032f9795..0404f550 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,7 @@ iced_lazy = "0.6.1" plotters-iced = "0.8.0" maxminddb = "0.23.0" confy = "0.5.1" -serde = { version = "1.0.163", default_features = false, features = ["derive", "rc"] } +serde = { version = "1.0.171", default_features = false, features = ["derive", "rc"] } rodio = { version = "0.17.1", default_features = false, features = ["mp3"] } reqwest = { version = "0.11.18", default-features = false, features = ["json", "blocking", "rustls-tls"] } dns-lookup = "2.0.2" @@ -53,8 +53,8 @@ toml = "0.7.4" #─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── [dev-dependencies] -rstest = "0.17.0" -serde_test = "1.0.163" +rstest = "0.18.1" +serde_test = "1.0.171" #─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── diff --git a/src/gui/pages/settings_style_page.rs b/src/gui/pages/settings_style_page.rs index c10c40b9..468c64b1 100644 --- a/src/gui/pages/settings_style_page.rs +++ b/src/gui/pages/settings_style_page.rs @@ -1,3 +1,4 @@ +use std::path::Path; use std::sync::Arc; use iced::alignment::{Horizontal, Vertical}; @@ -85,7 +86,7 @@ pub fn settings_style_page(sniffer: &Sniffer) -> Container { ); // Append custom style buttons if any exist - if let Some(custom_styles) = get_custom_styles(sniffer.language) { + if let Some(custom_styles) = custom_styles_conf_dir(sniffer.language) { content = content.push(vertical_space(Length::Fixed(10.0))); for child in custom_styles { content = content.push(child); @@ -193,22 +194,29 @@ fn get_palette(style: &Arc) -> Container<'static, Message> { )) } -// Load and process `CustomStyles`. -fn get_custom_styles(lang: Language) -> Option>> { - // Lazily load `CustomStyles` and process them into GUI elements. - let mut styles = confy::get_configuration_file_path("sniffnet", None) +#[inline] +fn custom_styles_conf_dir(lang: Language) -> Option>> { + confy::get_configuration_file_path("sniffnet", None) .ok() .and_then(|mut path| { path.pop(); path.push("themes"); - CustomStyle::from_dir(path).ok() - })? - .map(|style| { - let name = style.name.clone(); - let description = style.description(lang).to_owned(); - let style = Arc::new(StyleType::Custom(style)); - get_palette_container(&style, name, description, &style) - }); + load_custom_styles(path, lang) + }) +} + +// Load and process `CustomStyles`. +fn load_custom_styles

(path: P, lang: Language) -> Option>> +where + P: AsRef, +{ + // Lazily load `CustomStyles` and process them into GUI elements. + let mut styles = CustomStyle::from_dir(path.as_ref()).ok()?.map(|style| { + let name = style.name.clone(); + let description = style.description(lang).to_owned(); + let style = Arc::new(StyleType::Custom(style)); + get_palette_container(&style, name, description, &style) + }); // The easiest way to do this is with itertools, but I don't want to introduce another // dependency just for this one function. So I'll do it iteratively for now. @@ -244,3 +252,25 @@ fn get_custom_styles(lang: Language) -> Option>> { Some(children) } + +#[cfg(test)] +mod tests { + use std::{fs::read_dir, io}; + + use super::load_custom_styles; + use crate::Language; + + #[test] + fn test_deserialize_all_builtin_styles() -> Result<(), io::Error> { + let path = format!("{}/resources/themes", env!("CARGO_MANIFEST_DIR")); + // The counts `Result`, but that doesn't matter since none of the files should fail + let count = read_dir(&path)?.count(); + let themes = load_custom_styles(path, Language::EN) + .expect("should be able to read all of the custom themes"); + + // Make sure number of themes matches number of dir entries + assert_eq!(count, themes.len()); + + Ok(()) + } +} From e3d0d11c64b731988c386340da6dba49f0dc497b Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Wed, 26 Jul 2023 22:54:10 -0400 Subject: [PATCH 17/29] Make themes look a bit nicer. --- resources/themes/catppuccin_frappe.toml | 4 ++-- resources/themes/catppuccin_macchiato.toml | 4 ++-- resources/themes/dracula.toml | 18 ++++++++++++++++++ src/gui/styles/types/custom_style.rs | 2 ++ 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 resources/themes/dracula.toml diff --git a/resources/themes/catppuccin_frappe.toml b/resources/themes/catppuccin_frappe.toml index ec903cb3..c7b76982 100644 --- a/resources/themes/catppuccin_frappe.toml +++ b/resources/themes/catppuccin_frappe.toml @@ -8,12 +8,12 @@ PL = "Kojący pastelowy motyw dla porywczych" [palette] primary = "#303446" # Base -secondary = "#8caaee" # Blue +secondary = "#a6d189" # Green buttons = "#414559" # Surface0 outgoing = "#f4b8e4" # Pink text_headers = "#232634" # Crust text_body = "#c6d0f5" # Text -round_borders = "#babbf1" # Lavender +round_borders = "#99d1db" # Teal round_containers = "#292c3c" # Mantle starred = "#e5c890" # Yellow badge_alpha = 0.75 diff --git a/resources/themes/catppuccin_macchiato.toml b/resources/themes/catppuccin_macchiato.toml index fd433b3d..1d0c525b 100644 --- a/resources/themes/catppuccin_macchiato.toml +++ b/resources/themes/catppuccin_macchiato.toml @@ -8,9 +8,9 @@ PL = "Kojący pastelowy motyw dla porywczych" [palette] primary = "#24273a" # Base -secondary = "#8aadf4" # Blue +secondary = "#f5bde6" # Pink buttons = "#363a4f" # Surface0 -outgoing = "#f5bde6" # Pink +outgoing = "#c6a0f6" # Mauve text_headers = "#181926" # Crust text_body = "#cad3f5" # Text round_borders = "#b7bdf8" # Lavender diff --git a/resources/themes/dracula.toml b/resources/themes/dracula.toml new file mode 100644 index 00000000..17c23ff9 --- /dev/null +++ b/resources/themes/dracula.toml @@ -0,0 +1,18 @@ +# https://draculatheme.com/contribute +name = "Dracula" + +[description] +EN = "Dark theme for high productivity" + +[palette] +primary = "#44475a" # Current line +secondary = "#ff79c6" # Pink +buttons = "#6272a4" # Comment +outgoing = "#8be9fd" # Cyan +text_headers = "#44475a" # Current line +text_body = "#f8f8f2" # Foreground +round_borders = "#bd93f9" # Purple +round_containers = "#44475a" # Current line +starred = "#f1fa8c" # Yellow +badge_alpha = 0.75 +color_mix_chart = 0.3 diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 62df814c..2cec927f 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -91,6 +91,8 @@ impl CustomStyle { /// # Errors /// [io::Error] is only returned if `dir` can't be read. A best effort is made to read any styles /// present in the directory. + /// + /// Styles that cannot be read are ignored. pub fn from_dir

(dir: P) -> Result, io::Error> where P: Into, From eb4c1cec3390bc4a89cf8eefcc8f21be54a1a9de Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Mon, 25 Sep 2023 23:24:11 -0400 Subject: [PATCH 18/29] Clean up old custom style implementation. The newer implementation is much simpler, so only some of the code needs to be ported over. This is a WIP. The old tests don't work yet. --- README.md | 19 +-- src/gui/styles/types/custom_palette.rs | 172 ++++++++++++++++++++++++- src/gui/styles/types/custom_style.rs | 167 ------------------------ src/gui/styles/types/palette.rs | 9 ++ src/translations/translations.rs | 8 -- 5 files changed, 184 insertions(+), 191 deletions(-) diff --git a/README.md b/README.md index b5b9e3cd..0a3f7c0f 100644 --- a/README.md +++ b/README.md @@ -377,27 +377,18 @@ The currently usable hotkeys are reported in the following.

See details - Custom themes are specified as a TOML file that may be loaded from anywhere. Themes support multilingual - descriptions. + Custom themes are specified as a TOML file. The TOML must follow this format: ```toml name = "Catppuccin (Mocha)" - [description] - EN = "Catppuccin is a colorful, medium contrast pastel theme.\nhttps://github.com/catppuccin/catppuccin" - # Contributed by Emilia - HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" - # Contributed by Bartosz - PL = "Catppuccin to kolorowy i pastelowy motyw o średnim kontraście.\nhttps://github.com/catppuccin/catppuccin" - # Color palettes are in RGBA hexadecimal where the alpha is optional. [palette] primary = "#1e1e2e" # Base secondary = "#89b4fa" # Blue - buttons = "#313244" # Surface0 - incoming = "#89b4fa" # Blue outgoing = "#f5c2e7" # Pink + buttons = "#313244" # Surface0 text_headers = "#11111b" # Crust text_body = "#cdd6f4" # Text round_borders = "#74c7ec" # Sapphire @@ -438,7 +429,7 @@ branch, which uses the `glow` renderer. ||||||| ec3c96f In some cases, especially if you are running on an old architecture, the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) may cause some problems that could prevent you from running Sniffnet.
-In this case, you can try building the application from the [`glow-renderer`](https://github.com/GyulyVGC/sniffnet/tree/glow-renderer) +In this case, you can try building the application from the [`glow-renderer`](https://github.com/GyulyVGC/sniffnet/tree/glow-renderer) branch, which uses the `glow` renderer. > **Note** @@ -446,9 +437,9 @@ branch, which uses the `glow` renderer. > View issues labeled with [`renderer`](https://github.com/GyulyVGC/sniffnet/issues?q=is%3Aissue+label%3Arenderer) to see how those problems have been solved by others. ======= In some circumstances, especially if you are running on an old architecture or your graphical drivers are not up-to-date, -the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) +the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) may cause problems (country icons are completely black, or the interface glitches).
-In these cases you can download an alternative version of the application, +In these cases you can download an alternative version of the application, which is based on `tiny-skia`, a CPU-only software renderer that should work properly on every environment:
[Windows](https://github.com/GyulyVGC/sniffnet/suites/14909529200/artifacts/849640695) | [macOS](https://github.com/GyulyVGC/sniffnet/suites/14909529200/artifacts/849640694) | diff --git a/src/gui/styles/types/custom_palette.rs b/src/gui/styles/types/custom_palette.rs index 6a2d7f0a..a94f8b38 100644 --- a/src/gui/styles/types/custom_palette.rs +++ b/src/gui/styles/types/custom_palette.rs @@ -1,22 +1,35 @@ use std::fmt; +use std::fs::{self, File}; +use std::io::{self, BufReader, Read}; +use std::path::PathBuf; use iced::Color; -use serde::{Deserialize, Serialize}; +use serde::{de::Error as DeErrorTrait, Deserialize, Serialize}; +use super::color_remote::deserialize_color; use crate::gui::styles::custom_themes::{dracula, gruvbox, nord, solarized}; use crate::gui::styles::types::palette::Palette; /// Custom style with any relevant metadata +// NOTE: This is flattened for ergonomics. With flatten, both [Palette] and [PaletteExtension] can be +// defined in the TOML as a single entity rather than two separate tables. This is intentional because +// the separation between palette and its extension is an implementation detail that shouldn't be exposed +// to custom theme designers. +#[derive(Debug, Deserialize)] pub struct CustomPalette { - /// Color scheme's palette + /// Base colors for the theme + #[serde(flatten)] pub(crate) palette: Palette, /// Extra colors such as the favorites star + #[serde(flatten)] pub(crate) extension: PaletteExtension, } /// Extension color for themes. +#[derive(Debug, Deserialize)] pub struct PaletteExtension { /// Color of favorites star + #[serde(deserialize_with = "deserialize_color")] pub starred: Color, /// Badge/logo alpha pub chart_badge_alpha: f32, @@ -26,6 +39,55 @@ pub struct PaletteExtension { pub round_containers_alpha: f32, } +impl CustomPalette { + /// Deserialize [CustomPalette] from `path`. + /// + /// # Arguments + /// * `path` - Path to a UTF-8 encoded file containing a custom style as TOML. + pub fn from_file

(path: P) -> Result + where + P: Into, + { + // Try to open the file at `path` + let path = path.into(); + let mut toml_reader = File::open(path) + .map_err(DeErrorTrait::custom) + .map(BufReader::new)?; + + // Read the ostensible TOML + let mut style_toml = String::new(); + toml_reader + .read_to_string(&mut style_toml) + .map_err(DeErrorTrait::custom)?; + + // Deserialize it and store `path` into the resulting struct + // toml::de::from_str::(&style_toml).map(|mut style| { + // style.path = path; + // style + // }) + + toml::de::from_str(&style_toml) + } + + /// Load [CustomStyle]s from a directory. + /// + /// # Errors + /// [io::Error] is only returned if `dir` can't be read. A best effort is made to read any styles + /// present in the directory. + /// + /// Styles that cannot be read are ignored. + pub fn from_dir

(dir: P) -> Result, io::Error> + where + P: Into, + { + let iter = fs::read_dir(dir.into())?.filter_map(|entry| { + let entry = entry.ok()?.path(); + Self::from_file(entry.to_str()?).ok() + }); + Ok(iter) + } +} + /// Built in extra styles #[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash, PartialEq)] #[serde(tag = "custom")] @@ -112,3 +174,109 @@ impl fmt::Display for ExtraStyles { } } } + +#[cfg(test)] +mod tests { + use super::{ + deserialize_from_path, serialize_to_path, CustomPalette, Palette, PaletteExtension, + }; + use crate::{translations::types::language::Language, StyleType}; + use iced::color; + use serde::{Deserialize, Serialize}; + use serde_test::{assert_tokens, Token}; + use std::collections::BTreeMap; + + // Convenience struct for testing + #[derive(Debug, PartialEq, Deserialize, Serialize)] + #[serde(transparent)] + struct StyleForTests( + #[serde( + deserialize_with = "deserialize_from_path", + serialize_with = "serialize_to_path" + )] + CustomPalette, + ); + + // Test items + + // Replace with const format when it's stable + fn style_path() -> String { + format!( + "{}/resources/themes/catppuccin_mocha.toml", + env!("CARGO_MANIFEST_DIR") + ) + } + + // NOTE: This has to be updated if `resources/themes/catppuccin_mocha.toml` changes + fn catppuccin_style() -> StyleForTests { + StyleForTests(CustomPalette { + palette: Palette { + primary: color!(30, 30, 46), + secondary: color!(137, 180, 250), + buttons: color!(49, 50, 68), + outgoing: color!(245, 194, 231), + text_headers: color!(17, 17, 27), + text_body: color!(205, 214, 244), + round_borders: color!(180, 190, 254), + round_containers: color!(24, 24, 37), + }, + extension: PaletteExtension { + starred: color!(249, 226, 175), + badge_alpha: 0.75, + color_mix_chart: 0.3, + }, + }) + } + + // Test that split deserialization works for `CustomStyle`. + // This is different than testing that `StyleType` properly deserializes. + #[test] + fn test_customstyle_split_de() { + let style_test = catppuccin_style(); + // This is only used for the test which requires an &'static str. + let path: &'static str = Box::leak(style_path().into_boxed_str()); + assert_tokens(&style_test, &[Token::String(path)]); + } + + // Ensure that StyleType itself still deserializes properly + #[test] + fn test_styletype_unit_split_de() { + // Unit variant without a struct + assert_tokens( + &StyleType::DeepSea, + &[ + Token::Struct { + name: "StyleType", + len: 1, + }, + Token::Str("style"), + Token::Str("DeepSea"), + Token::StructEnd, + ], + ); + } + + // Test that StyleType::Custom successfully deserializes. + // Originally, StyleType::Custom did not ser/de correctly because of how TOML + // handles enums. + #[test] + fn test_styletype_custom_split_de() { + // CustomStyle + // This is only used for the test so leaking it is fine. + let path = &*Box::leak(style_path().into_boxed_str()); + assert_tokens( + &StyleType::Custom(catppuccin_style().0), + &[ + Token::Struct { + name: "StyleType", + len: 2, + }, + Token::Str("style"), + Token::Str("Custom"), + Token::Str("path"), + Token::Str(path), + Token::StructEnd, + ], + ); + } +} diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs index 2cec927f..a0b11738 100644 --- a/src/gui/styles/types/custom_style.rs +++ b/src/gui/styles/types/custom_style.rs @@ -59,50 +59,7 @@ pub struct CustomStyle { } impl CustomStyle { - /// Deserialize [CustomStyle] from `path`. - /// - /// # Arguments - /// * `path` - Path to a UTF-8 encoded file containing a custom style as TOML. - pub fn from_file

(path: P) -> Result - where - P: Into, - { - // Try to open the file at `path` - let path = path.into(); - let mut toml_reader = File::open(&path) - .map_err(DeErrorTrait::custom) - .map(BufReader::new)?; - - // Read the ostensible TOML - let mut style_toml = String::new(); - toml_reader - .read_to_string(&mut style_toml) - .map_err(DeErrorTrait::custom)?; - // Deserialize it and store `path` into the resulting struct - toml::de::from_str::(&style_toml).map(|mut style| { - style.path = path; - style - }) - } - - /// Load [CustomStyle]s from a directory. - /// - /// # Errors - /// [io::Error] is only returned if `dir` can't be read. A best effort is made to read any styles - /// present in the directory. - /// - /// Styles that cannot be read are ignored. - pub fn from_dir

(dir: P) -> Result, io::Error> - where - P: Into, - { - let iter = fs::read_dir(dir.into())?.filter_map(|entry| { - let entry = entry.ok()?.path(); - Self::from_file(entry.to_str()?).ok() - }); - Ok(iter) - } /// Return translated description or a default. /// @@ -124,10 +81,6 @@ impl CustomStyle { } /// Base [Palette] and extension colors for [CustomStyle]. -// NOTE: This is flattened for ergonomics. With flatten, both [Palette] and [PaletteExtension] can be -// defined in the TOML as a single entity rather than two separate tables. This is intentional because -// the separation between palette and its extension is an implementation detail that shouldn't be exposed -// to custom theme designers. // // Clippy complains about deriving [Hash] with a manually written [PartialEq]. We manually implemented // Hash for [Palette] and [PaletteExtension], so deriving Hash is convenient and the error is spurious. @@ -166,124 +119,4 @@ where serializer.serialize_str(&style.path) } -#[cfg(test)] -mod tests { - use super::{ - deserialize_from_path, serialize_to_path, CustomPalette, CustomStyle, Palette, - PaletteExtension, - }; - use crate::{translations::types::language::Language, StyleType}; - use iced::color; - use serde::{Deserialize, Serialize}; - use serde_test::{assert_tokens, Token}; - use std::collections::BTreeMap; - - // Convenience struct for testing - #[derive(Debug, PartialEq, Deserialize, Serialize)] - #[serde(transparent)] - struct StyleForTests( - #[serde( - deserialize_with = "deserialize_from_path", - serialize_with = "serialize_to_path" - )] - CustomStyle, - ); - // Test items - - // Replace with const format when it's stable - fn style_path() -> String { - format!( - "{}/resources/themes/catppuccin_mocha.toml", - env!("CARGO_MANIFEST_DIR") - ) - } - - const STYLE_DESC_ENG: &str = "Soothing pastel theme for the high-spirited!"; - // Hungarian translation by Emi. - const STYLE_DESC_HU: &str = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin"; - // Polish translation by Bartosz. - const STYLE_DESC_PL: &str = "Kojący pastelowy motyw dla porywczych"; - - // NOTE: This has to be updated if `resources/themes/catppuccin_mocha.toml` changes - fn catppuccin_style() -> StyleForTests { - StyleForTests(CustomStyle { - name: "Catppuccin (Mocha)".to_owned(), - path: style_path(), - description: BTreeMap::from([ - (Language::EN, STYLE_DESC_ENG.to_owned()), - // (Language::HU, STYLE_DESC_HU.to_owned()), - (Language::PL, STYLE_DESC_PL.to_owned()), - ]), - palette: CustomPalette { - base: Palette { - primary: color!(30, 30, 46), - secondary: color!(137, 180, 250), - buttons: color!(49, 50, 68), - outgoing: color!(245, 194, 231), - text_headers: color!(17, 17, 27), - text_body: color!(205, 214, 244), - round_borders: color!(180, 190, 254), - round_containers: color!(24, 24, 37), - }, - extension: PaletteExtension { - starred: color!(249, 226, 175), - badge_alpha: 0.75, - color_mix_chart: 0.3, - }, - }, - }) - } - - // Test that split deserialization works for `CustomStyle`. - // This is different than testing that `StyleType` properly deserializes. - #[test] - fn test_customstyle_split_de() { - let style_test = catppuccin_style(); - // This is only used for the test which requires an &'static str. - let path: &'static str = Box::leak(style_path().into_boxed_str()); - assert_tokens(&style_test, &[Token::String(path)]); - } - - // Ensure that StyleType itself still deserializes properly - #[test] - fn test_styletype_unit_split_de() { - // Unit variant without a struct - assert_tokens( - &StyleType::DeepSea, - &[ - Token::Struct { - name: "StyleType", - len: 1, - }, - Token::Str("style"), - Token::Str("DeepSea"), - Token::StructEnd, - ], - ); - } - - // Test that StyleType::Custom successfully deserializes. - // Originally, StyleType::Custom did not ser/de correctly because of how TOML - // handles enums. - #[test] - fn test_styletype_custom_split_de() { - // CustomStyle - // This is only used for the test so leaking it is fine. - let path = &*Box::leak(style_path().into_boxed_str()); - assert_tokens( - &StyleType::Custom(catppuccin_style().0), - &[ - Token::Struct { - name: "StyleType", - len: 2, - }, - Token::Str("style"), - Token::Str("Custom"), - Token::Str("path"), - Token::Str(path), - Token::StructEnd, - ], - ); - } -} diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 5328a1a8..75b154d8 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -2,7 +2,9 @@ use iced::Color; use plotters::style::RGBColor; +use serde::Deserialize; +use super::color_remote::deserialize_color; use crate::gui::styles::style_constants::{ DAY_STYLE, DEEP_SEA_STYLE, MON_AMOUR_STYLE, NIGHT_STYLE, }; @@ -16,18 +18,25 @@ use crate::StyleType; /// - `secondary` and `outgoing` should be complementary colors if possible /// - `text_headers` should be black or white and must have a strong contrast with `secondary` /// - `text_body` should be black or white and must have a strong contrast with `primary` +#[derive(Debug, Deserialize)] pub struct Palette { /// Main color of the GUI (background, hovered buttons, active tab) + #[serde(deserialize_with = "deserialize_color")] pub primary: Color, /// Secondary color of the GUI (incoming connections, header, footer, buttons' borders, radio selection) + #[serde(deserialize_with = "deserialize_color")] pub secondary: Color, /// Color of outgoing connections + #[serde(deserialize_with = "deserialize_color")] pub outgoing: Color, /// Color of active buttons (when not hovered) and inactive tabs + #[serde(deserialize_with = "deserialize_color")] pub buttons: Color, /// Color of header and footer text + #[serde(deserialize_with = "deserialize_color")] pub text_headers: Color, /// Color of body and buttons text + #[serde(deserialize_with = "deserialize_color")] pub text_body: Color, } diff --git a/src/translations/translations.rs b/src/translations/translations.rs index 6240ebb2..45cecd33 100644 --- a/src/translations/translations.rs +++ b/src/translations/translations.rs @@ -1880,11 +1880,3 @@ pub fn only_last_30_translation(language: Language) -> &'static str { Language::JA => "最新の通知 30 件のみ表示されます", } } - -pub fn custom_theme_path(language: Language) -> &'static str { - // Currently only English because it's a new text - match language { - Language::EN => "Path to a custom theme and hit enter!", - _ => custom_theme_path(Language::EN), - } -} From e9e097fc304e52cddb1e45133fbfb7f01e054dc6 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Thu, 28 Sep 2023 03:07:04 -0400 Subject: [PATCH 19/29] Add `CustomToml` to `ExtraStyles`. The least invasive way of supporting custom TOML themes is to add a new variant to `ExtraStyles`. I implemented `Hash` for `CustomPalette` because it's not derivable for `Palette`. Finally, indicating whether a style is nightly must be stored in the palette extensions struct because I can't hard code it (the old solution for the built in extra styles). --- src/configs/types/config_advanced_settings.rs | 2 + src/configs/types/configs.rs | 15 +++- src/gui/styles/custom_themes/dracula.rs | 2 + src/gui/styles/custom_themes/gruvbox.rs | 2 + src/gui/styles/custom_themes/nord.rs | 2 + src/gui/styles/custom_themes/solarized.rs | 2 + src/gui/styles/types/custom_palette.rs | 78 ++++++++++++++----- src/gui/styles/types/palette.rs | 2 +- 8 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/configs/types/config_advanced_settings.rs b/src/configs/types/config_advanced_settings.rs index a71e2e5f..7f66fb59 100644 --- a/src/configs/types/config_advanced_settings.rs +++ b/src/configs/types/config_advanced_settings.rs @@ -11,6 +11,7 @@ pub struct ConfigAdvancedSettings { pub mmdb_country: String, pub mmdb_asn: String, pub output_path: PathBuf, + pub style_path: Option } impl ConfigAdvancedSettings { @@ -42,6 +43,7 @@ impl Default for ConfigAdvancedSettings { mmdb_country: String::new(), mmdb_asn: String::new(), output_path: get_default_report_directory(), + style_path: None } } } diff --git a/src/configs/types/configs.rs b/src/configs/types/configs.rs index b53c6097..585287a9 100644 --- a/src/configs/types/configs.rs +++ b/src/configs/types/configs.rs @@ -1,3 +1,5 @@ +use crate::gui::styles::types::custom_palette::{CustomPalette, ExtraStyles}; +use crate::gui::styles::types::style_type::StyleType; use crate::{ConfigAdvancedSettings, ConfigDevice, ConfigSettings, ConfigWindow}; #[derive(Default)] @@ -10,10 +12,19 @@ pub struct Configs { impl Configs { pub fn load() -> Self { + let mut settings = ConfigSettings::load(); + let advanced_settings = ConfigAdvancedSettings::load(); + + if let Some(style_path) = &advanced_settings.style_path { + settings.style = CustomPalette::from_file(style_path) + .map(|palette| StyleType::Custom(ExtraStyles::CustomToml(palette))) + .unwrap_or_default() + } + Configs { - settings: ConfigSettings::load(), + settings, device: ConfigDevice::load(), - advanced_settings: ConfigAdvancedSettings::load(), + advanced_settings, window: ConfigWindow::load(), } } diff --git a/src/gui/styles/custom_themes/dracula.rs b/src/gui/styles/custom_themes/dracula.rs index 58fcdf4b..87b9e4af 100644 --- a/src/gui/styles/custom_themes/dracula.rs +++ b/src/gui/styles/custom_themes/dracula.rs @@ -23,6 +23,7 @@ pub(in crate::gui::styles) fn dracula_dark() -> CustomPalette { round_borders_alpha: 0.1, round_containers_alpha: 0.04, chart_badge_alpha: 0.15, + nightly: true }, } } @@ -43,6 +44,7 @@ pub(in crate::gui::styles) fn dracula_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.45, round_containers_alpha: 0.25, + nightly: true }, } } diff --git a/src/gui/styles/custom_themes/gruvbox.rs b/src/gui/styles/custom_themes/gruvbox.rs index 2cd7b9fc..803d763f 100644 --- a/src/gui/styles/custom_themes/gruvbox.rs +++ b/src/gui/styles/custom_themes/gruvbox.rs @@ -24,6 +24,7 @@ pub(in crate::gui::styles) fn gruvbox_dark() -> CustomPalette { chart_badge_alpha: 0.15, round_borders_alpha: 0.12, round_containers_alpha: 0.05, + nightly: true, }, } } @@ -44,6 +45,7 @@ pub(in crate::gui::styles) fn gruvbox_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.45, round_containers_alpha: 0.2, + nightly: true, }, } } diff --git a/src/gui/styles/custom_themes/nord.rs b/src/gui/styles/custom_themes/nord.rs index e6016595..af4cac08 100644 --- a/src/gui/styles/custom_themes/nord.rs +++ b/src/gui/styles/custom_themes/nord.rs @@ -22,6 +22,7 @@ pub(in crate::gui::styles) fn nord_dark() -> CustomPalette { chart_badge_alpha: 0.2, round_borders_alpha: 0.35, round_containers_alpha: 0.15, + nightly: true, }, } } @@ -41,6 +42,7 @@ pub(in crate::gui::styles) fn nord_light() -> CustomPalette { chart_badge_alpha: 0.6, round_borders_alpha: 0.35, round_containers_alpha: 0.15, + nightly: true, }, } } diff --git a/src/gui/styles/custom_themes/solarized.rs b/src/gui/styles/custom_themes/solarized.rs index 8d09fa7f..24125541 100644 --- a/src/gui/styles/custom_themes/solarized.rs +++ b/src/gui/styles/custom_themes/solarized.rs @@ -23,6 +23,7 @@ pub(in crate::gui::styles) fn solarized_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.35, round_containers_alpha: 0.15, + nightly: true, }, } } @@ -43,6 +44,7 @@ pub(in crate::gui::styles) fn solarized_dark() -> CustomPalette { chart_badge_alpha: 0.25, round_borders_alpha: 0.15, round_containers_alpha: 0.08, + nightly: true, }, } } diff --git a/src/gui/styles/types/custom_palette.rs b/src/gui/styles/types/custom_palette.rs index a94f8b38..413f1633 100644 --- a/src/gui/styles/types/custom_palette.rs +++ b/src/gui/styles/types/custom_palette.rs @@ -1,21 +1,24 @@ use std::fmt; use std::fs::{self, File}; +use std::hash::{Hash, Hasher}; use std::io::{self, BufReader, Read}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use iced::Color; use serde::{de::Error as DeErrorTrait, Deserialize, Serialize}; -use super::color_remote::deserialize_color; +use super::color_remote::{color_hash, deserialize_color}; use crate::gui::styles::custom_themes::{dracula, gruvbox, nord, solarized}; use crate::gui::styles::types::palette::Palette; +const FLOAT_PRECISION: f32 = 10000.0; + /// Custom style with any relevant metadata // NOTE: This is flattened for ergonomics. With flatten, both [Palette] and [PaletteExtension] can be // defined in the TOML as a single entity rather than two separate tables. This is intentional because // the separation between palette and its extension is an implementation detail that shouldn't be exposed // to custom theme designers. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct CustomPalette { /// Base colors for the theme #[serde(flatten)] @@ -26,7 +29,7 @@ pub struct CustomPalette { } /// Extension color for themes. -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct PaletteExtension { /// Color of favorites star #[serde(deserialize_with = "deserialize_color")] @@ -37,6 +40,8 @@ pub struct PaletteExtension { pub round_borders_alpha: f32, /// Round containers alpha pub round_containers_alpha: f32, + /// Nightly (dark) style + pub nightly: bool, } impl CustomPalette { @@ -46,10 +51,9 @@ impl CustomPalette { /// * `path` - Path to a UTF-8 encoded file containing a custom style as TOML. pub fn from_file

(path: P) -> Result where - P: Into, + P: AsRef, { // Try to open the file at `path` - let path = path.into(); let mut toml_reader = File::open(path) .map_err(DeErrorTrait::custom) .map(BufReader::new)?; @@ -88,8 +92,49 @@ impl CustomPalette { } } +impl Hash for CustomPalette { + fn hash(&self, state: &mut H) { + let Self { palette, extension } = self; + + let Palette { + primary, + secondary, + outgoing, + buttons, + text_headers, + text_body, + } = palette; + + color_hash(*primary, state); + color_hash(*secondary, state); + color_hash(*outgoing, state); + color_hash(*buttons, state); + color_hash(*text_headers, state); + color_hash(*text_body, state); + + extension.hash(state) + } +} + +impl Hash for PaletteExtension { + fn hash(&self, state: &mut H) { + let Self { + starred, + chart_badge_alpha, + round_borders_alpha, + round_containers_alpha, + .. + } = self; + + color_hash(*starred, state); + ((*chart_badge_alpha * FLOAT_PRECISION).trunc() as u32).hash(state); + ((*round_borders_alpha * FLOAT_PRECISION).trunc() as u32).hash(state); + ((*round_containers_alpha * FLOAT_PRECISION).trunc() as u32).hash(state); + } +} + /// Built in extra styles -#[derive(Clone, Copy, Serialize, Deserialize, Debug, Hash, PartialEq)] +#[derive(Clone, Copy, Debug, Hash, PartialEq, Serialize, Deserialize)] #[serde(tag = "custom")] pub enum ExtraStyles { DraculaDark, @@ -100,6 +145,8 @@ pub enum ExtraStyles { NordLight, SolarizedDark, SolarizedLight, + #[serde(skip)] + CustomToml(CustomPalette), } impl ExtraStyles { @@ -114,6 +161,7 @@ impl ExtraStyles { ExtraStyles::NordDark => nord::nord_dark().palette, ExtraStyles::SolarizedDark => solarized::solarized_dark().palette, ExtraStyles::SolarizedLight => solarized::solarized_light().palette, + ExtraStyles::CustomToml(user) => user.palette, } } @@ -128,21 +176,13 @@ impl ExtraStyles { ExtraStyles::NordDark => nord::nord_dark().extension, ExtraStyles::SolarizedDark => solarized::solarized_dark().extension, ExtraStyles::SolarizedLight => solarized::solarized_light().extension, + ExtraStyles::CustomToml(user) => user.extension, } } /// Theme is a night/dark style - pub const fn is_nightly(self) -> bool { - match self { - ExtraStyles::DraculaDark - | ExtraStyles::GruvboxDark - | ExtraStyles::NordDark - | ExtraStyles::SolarizedDark => true, - ExtraStyles::DraculaLight - | ExtraStyles::GruvboxLight - | ExtraStyles::NordLight - | ExtraStyles::SolarizedLight => false, - } + pub fn is_nightly(self) -> bool { + self.to_ext().nightly } /// Slice of all implemented custom styles @@ -171,6 +211,8 @@ impl fmt::Display for ExtraStyles { ExtraStyles::NordDark => write!(f, "Nord (Night)"), ExtraStyles::SolarizedLight => write!(f, "Solarized (Day)"), ExtraStyles::SolarizedDark => write!(f, "Solarized (Night)"), + // Custom style names aren't used anywhere so this shouldn't be reached + _ => unreachable!(), } } } diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 75b154d8..ee3ec15f 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -18,7 +18,7 @@ use crate::StyleType; /// - `secondary` and `outgoing` should be complementary colors if possible /// - `text_headers` should be black or white and must have a strong contrast with `secondary` /// - `text_body` should be black or white and must have a strong contrast with `primary` -#[derive(Debug, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] pub struct Palette { /// Main color of the GUI (background, hovered buttons, active tab) #[serde(deserialize_with = "deserialize_color")] From 475856b7c44ceae4d3d55cac6e2ebba9d3afd7d5 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Fri, 29 Sep 2023 01:29:42 -0400 Subject: [PATCH 20/29] Add an element for loading custom styles (Message not implemented yet) --- src/gui/pages/settings_advanced_page.rs | 39 ++++++++++++++++++++++++- src/gui/types/message.rs | 2 ++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/gui/pages/settings_advanced_page.rs b/src/gui/pages/settings_advanced_page.rs index 36dc44d9..7cce62c5 100644 --- a/src/gui/pages/settings_advanced_page.rs +++ b/src/gui/pages/settings_advanced_page.rs @@ -24,7 +24,7 @@ use iced::widget::{ }; use iced::Length::Fixed; use iced::{Alignment, Font, Length, Renderer}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::sync::Arc; pub fn settings_advanced_page(sniffer: &Sniffer) -> Container> { @@ -83,6 +83,12 @@ pub fn settings_advanced_page(sniffer: &Sniffer) -> Container, + caption: &str, +) -> Row<'static, Message, Renderer> { + let is_error = if custom_path.is_some() { false } else { true }; + + let mut input = TextInput::new( + "-", + &custom_path.map(Path::to_string_lossy).unwrap_or_default(), + ) + .padding([0, 5]) + .font(font) + .width(Length::Fixed(200.0)) + .style(if is_error { + TextInputType::Error + } else { + TextInputType::Standard + }); + + if is_editable { + input = input.on_input(Message::LoadStyle); + } + + Row::new() + .spacing(5) + .push(Text::new(format!("{caption}:")).font(font)) + .push(input) +} diff --git a/src/gui/types/message.rs b/src/gui/types/message.rs index b18d5493..1f575578 100644 --- a/src/gui/types/message.rs +++ b/src/gui/types/message.rs @@ -43,6 +43,8 @@ pub enum Message { Reset, /// Change application style Style(StyleType), + /// Deserialize a style from a path + LoadStyle(String), /// Manage waiting time Waiting, /// Displays a modal From 86e4efa6b37c11fee021e7113b6b6f236ad44edc Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Sat, 30 Sep 2023 02:43:49 -0400 Subject: [PATCH 21/29] Implement Message::LoadStyle. --- resources/themes/dracula.toml | 28 +++++++++++----------------- src/configs/types/configs.rs | 7 +++++-- src/gui/types/sniffer.rs | 15 +++++++++++++++ 3 files changed, 31 insertions(+), 19 deletions(-) diff --git a/resources/themes/dracula.toml b/resources/themes/dracula.toml index 17c23ff9..114a8645 100644 --- a/resources/themes/dracula.toml +++ b/resources/themes/dracula.toml @@ -1,18 +1,12 @@ -# https://draculatheme.com/contribute -name = "Dracula" - -[description] -EN = "Dark theme for high productivity" - [palette] -primary = "#44475a" # Current line -secondary = "#ff79c6" # Pink -buttons = "#6272a4" # Comment -outgoing = "#8be9fd" # Cyan -text_headers = "#44475a" # Current line -text_body = "#f8f8f2" # Foreground -round_borders = "#bd93f9" # Purple -round_containers = "#44475a" # Current line -starred = "#f1fa8c" # Yellow -badge_alpha = 0.75 -color_mix_chart = 0.3 +primary = "#44475a" # Current line +secondary = "#ff79c6" # Pink +buttons = "#6272a4" # Comment +outgoing = "#8be9fd" # Cyan +text_headers = "#282a36" # Background +text_body = "#f8f8f2" # Foreground +starred = "#f1fa8cb2" # Yellow +round_borders_alpha = 0.1 +round_containers_alpha = 0.04 +chart_badge_alpha = 0.15 +nightly = true diff --git a/src/configs/types/configs.rs b/src/configs/types/configs.rs index 585287a9..dc134e15 100644 --- a/src/configs/types/configs.rs +++ b/src/configs/types/configs.rs @@ -16,9 +16,12 @@ impl Configs { let advanced_settings = ConfigAdvancedSettings::load(); if let Some(style_path) = &advanced_settings.style_path { - settings.style = CustomPalette::from_file(style_path) + // Don't clobber the previously set style if the path is broken + if let Ok(style) = CustomPalette::from_file(style_path) .map(|palette| StyleType::Custom(ExtraStyles::CustomToml(palette))) - .unwrap_or_default() + { + settings.style = style; + } } Configs { diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index 89752890..b961c747 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -16,6 +16,7 @@ use crate::countries::country_utils::COUNTRY_MMDB; use crate::gui::components::types::my_modal::MyModal; use crate::gui::pages::types::running_page::RunningPage; use crate::gui::pages::types::settings_page::SettingsPage; +use crate::gui::styles::types::custom_palette::{CustomPalette, ExtraStyles}; use crate::gui::styles::types::gradient_type::GradientType; use crate::gui::types::message::Message; use crate::gui::types::status::Status; @@ -177,6 +178,20 @@ impl Sniffer { self.style = style; self.traffic_chart.change_style(self.style); } + Message::LoadStyle(path) => { + self.advanced_settings.style_path = if !path.is_empty() { + Some(path.into()) + } else { + None + }; + + if let Some(path) = self.advanced_settings.style_path.as_deref() { + if let Ok(palette) = CustomPalette::from_file(path) { + let style = StyleType::Custom(ExtraStyles::CustomToml(palette)); + return self.update(Message::Style(style)); + } + } + } Message::Waiting => self.update_waiting_dots(), Message::AddOrRemoveFavorite(host, add) => self.add_or_remove_favorite(&host, add), Message::ShowModal(modal) => { From f32aa7c2e7b2a2e60508189622158492349e99ad Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Sun, 1 Oct 2023 01:06:23 -0400 Subject: [PATCH 22/29] Improve custom theme loading in GUI - The custom theme text box is highlighted in red if the path doesn't exist or if it doesn't have a `.toml` extension. - The last set theme takes prescedence instead of custom themes always clobbering the set theme. - Fix all old TOML themes. --- resources/themes/catppuccin_frappe.toml | 30 +++++++------------ resources/themes/catppuccin_latte.toml | 34 ++++++++-------------- resources/themes/catppuccin_macchiato.toml | 30 +++++++------------ resources/themes/catppuccin_mocha.toml | 32 +++++++------------- resources/themes/dracula.toml | 1 - src/gui/pages/settings_advanced_page.rs | 5 ++-- src/gui/types/sniffer.rs | 6 +++- 7 files changed, 53 insertions(+), 85 deletions(-) diff --git a/resources/themes/catppuccin_frappe.toml b/resources/themes/catppuccin_frappe.toml index c7b76982..64d026a4 100644 --- a/resources/themes/catppuccin_frappe.toml +++ b/resources/themes/catppuccin_frappe.toml @@ -1,20 +1,12 @@ # https://github.com/catppuccin/catppuccin -name = "Catppuccin (Frappé)" - -[description] -EN = "Soothing pastel theme for the high-spirited!" -# Contributed by Bartosz -PL = "Kojący pastelowy motyw dla porywczych" - -[palette] -primary = "#303446" # Base -secondary = "#a6d189" # Green -buttons = "#414559" # Surface0 -outgoing = "#f4b8e4" # Pink -text_headers = "#232634" # Crust -text_body = "#c6d0f5" # Text -round_borders = "#99d1db" # Teal -round_containers = "#292c3c" # Mantle -starred = "#e5c890" # Yellow -badge_alpha = 0.75 -color_mix_chart = 0.3 +primary = "#303446" # Base +secondary = "#a6d189" # Green +buttons = "#414559" # Surface0 +outgoing = "#f4b8e4" # Pink +text_headers = "#232634" # Crust +text_body = "#c6d0f5" # Text +starred = "#e5c890" # Yellow +round_borders_alpha = 0.1 +round_containers_alpha = 0.04 +chart_badge_alpha = 0.55 +nightly = true diff --git a/resources/themes/catppuccin_latte.toml b/resources/themes/catppuccin_latte.toml index 6e18e999..566e1973 100644 --- a/resources/themes/catppuccin_latte.toml +++ b/resources/themes/catppuccin_latte.toml @@ -1,22 +1,12 @@ -# https://github.com/catppuccin/catppuccin -name = "Catppuccin (Latte)" - -[description] -EN = "Soothing pastel theme for the high-spirited!" -# Contributed by Emilia -# HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" -# Contributed by Bartosz -PL = "Kojący pastelowy motyw dla porywczych" - -[palette] -primary = "#eff1f5" # Base -secondary = "#1e66f5" # Blue -buttons = "#ccd0da" # Surface0 -outgoing = "#ea76cb" # Pink -text_headers = "#dce0e8" # Crust -text_body = "#4c4f69" # Text -round_borders = "#7287fd" # Lavender -round_containers = "#e6e9ef" # Mantle -starred = "#df8e1d" # Yellow -badge_alpha = 0.75 -color_mix_chart = 0.3 +# https://github.com/catppuccin/catppuccin" +primary = "#eff1f5" # Base +secondary = "#1e66f5" # Blue +buttons = "#ccd0da" # Surface0 +outgoing = "#ea76cb" # Pink +text_headers = "#dce0e8" # Crust +text_body = "#4c4f69" # Text +starred = "#df8e1d" # Yellow +round_borders_alpha = 0.15 +round_containers_alpha = 0.25 +chart_badge_alpha = 0.75 +nightly = false diff --git a/resources/themes/catppuccin_macchiato.toml b/resources/themes/catppuccin_macchiato.toml index 1d0c525b..7c31f684 100644 --- a/resources/themes/catppuccin_macchiato.toml +++ b/resources/themes/catppuccin_macchiato.toml @@ -1,20 +1,12 @@ # https://github.com/catppuccin/catppuccin -name = "Catppuccin (Macchiato)" - -[description] -EN = "Soothing pastel theme for the high-spirited!" -# Contributed by Bartosz -PL = "Kojący pastelowy motyw dla porywczych" - -[palette] -primary = "#24273a" # Base -secondary = "#f5bde6" # Pink -buttons = "#363a4f" # Surface0 -outgoing = "#c6a0f6" # Mauve -text_headers = "#181926" # Crust -text_body = "#cad3f5" # Text -round_borders = "#b7bdf8" # Lavender -round_containers = "#1e2030" # Mantle -starred = "#eed49f" # Yellow -badge_alpha = 0.75 -color_mix_chart = 0.3 +primary = "#24273a" # Base +secondary = "#f5bde6" # Pink +buttons = "#363a4f" # Surface0 +outgoing = "#c6a0f6" # Mauve +text_headers = "#181926" # Crust +text_body = "#cad3f5" # Text +starred = "#eed49f" # Yellow +round_borders_alpha = 0.1 +round_containers_alpha = 0.15 +chart_badge_alpha = 0.75 +nightly = true diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index 20f5639d..488af0b0 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -1,22 +1,12 @@ # https://github.com/catppuccin/catppuccin -name = "Catppuccin (Mocha)" - -[description] -EN = "Soothing pastel theme for the high-spirited!" -# Contributed by Emilia -# HU = "Catpuccin egy színes, közepes kontrasztú, pasztell téma.\nhttps://github.com/catppuccin/catppuccin" -# Contributed by Bartosz -PL = "Kojący pastelowy motyw dla porywczych" - -[palette] -primary = "#1e1e2e" # Base -secondary = "#89b4fa" # Blue -buttons = "#313244" # Surface0 -outgoing = "#f5c2e7" # Pink -text_headers = "#11111b" # Crust -text_body = "#cdd6f4" # Text -round_borders = "#b4befe" # Lavender -round_containers = "#181825" # Mantle -starred = "#f9e2af" # Yellow -badge_alpha = 0.75 -color_mix_chart = 0.3 +primary = "#1e1e2e" # Base +secondary = "#89b4fa" # Blue +buttons = "#313244" # Surface0 +outgoing = "#f5c2e7" # Pink +text_headers = "#11111b" # Crust +text_body = "#cdd6f4" # Text +starred = "#f9e2af" # Yellow +round_borders_alpha = 0.1 +round_containers_alpha = 0.15 +chart_badge_alpha = 0.75 +nightly = true diff --git a/resources/themes/dracula.toml b/resources/themes/dracula.toml index 114a8645..ebc529bc 100644 --- a/resources/themes/dracula.toml +++ b/resources/themes/dracula.toml @@ -1,4 +1,3 @@ -[palette] primary = "#44475a" # Current line secondary = "#ff79c6" # Pink buttons = "#6272a4" # Comment diff --git a/src/gui/pages/settings_advanced_page.rs b/src/gui/pages/settings_advanced_page.rs index 7cce62c5..cd68fb7f 100644 --- a/src/gui/pages/settings_advanced_page.rs +++ b/src/gui/pages/settings_advanced_page.rs @@ -88,7 +88,7 @@ pub fn settings_advanced_page(sniffer: &Sniffer) -> Container, caption: &str, ) -> Row<'static, Message, Renderer> { - let is_error = if custom_path.is_some() { false } else { true }; + let is_error = custom_path + .is_some_and(|path| path.extension().map_or(true, |ext| ext != "toml") || !path.exists()); let mut input = TextInput::new( "-", diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index b961c747..31afd1f8 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -175,6 +175,9 @@ impl Sniffer { Message::Start => self.start(), Message::Reset => return self.reset(), Message::Style(style) => { + // Reset the path for custom styles so that the newly chosen theme loads when sniffnet starts + // Without this, the custom style will always be set on launch regardless of a set theme + self.advanced_settings.style_path = None; self.style = style; self.traffic_chart.change_style(self.style); } @@ -188,7 +191,8 @@ impl Sniffer { if let Some(path) = self.advanced_settings.style_path.as_deref() { if let Ok(palette) = CustomPalette::from_file(path) { let style = StyleType::Custom(ExtraStyles::CustomToml(palette)); - return self.update(Message::Style(style)); + self.style = style; + self.traffic_chart.change_style(self.style); } } } From 6f320a85a5b6828dc4536ff46403fe7bed63c43f Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Sun, 1 Oct 2023 01:26:54 -0400 Subject: [PATCH 23/29] Update readme to use the latest theme spec --- README.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 0a3f7c0f..43aca0f0 100644 --- a/README.md +++ b/README.md @@ -381,23 +381,22 @@ The currently usable hotkeys are reported in the following. The TOML must follow this format: ```toml - name = "Catppuccin (Mocha)" - # Color palettes are in RGBA hexadecimal where the alpha is optional. - [palette] - primary = "#1e1e2e" # Base - secondary = "#89b4fa" # Blue - outgoing = "#f5c2e7" # Pink - buttons = "#313244" # Surface0 - text_headers = "#11111b" # Crust - text_body = "#cdd6f4" # Text - round_borders = "#74c7ec" # Sapphire - round_containers = "#585b70" # Surface 2 - starred = "#f9e2af" # Yellow + primary = "#1e1e2e" # Base + secondary = "#89b4fa" # Blue + buttons = "#313244" # Surface0 + outgoing = "#f5c2e7" # Pink + text_headers = "#11111b" # Crust + text_body = "#cdd6f4" # Text + starred = "#f9e2af" # Yellow # Alpha channels are floats within [0.0, 1.0] - badge_alpha = 0.75 - color_mix_chart = 0.3 + round_borders_alpha = 0.1 + round_containers_alpha = 0.15 + chart_badge_alpha = 0.75 + + # Night or dark themes should be specified here + nightly = true ``` The example theme above uses colors from [Catppuccin Mocha](https://github.com/catppuccin/catppuccin). From 30e1a01e1f17d3219a74763a040163002c7002f3 Mon Sep 17 00:00:00 2001 From: Josh Megnauth Date: Mon, 2 Oct 2023 01:29:12 -0400 Subject: [PATCH 24/29] Clean up tests and code. --- src/gui/styles/types/custom_palette.rs | 126 ++++--------------------- src/gui/styles/types/custom_style.rs | 122 ------------------------ 2 files changed, 20 insertions(+), 228 deletions(-) delete mode 100644 src/gui/styles/types/custom_style.rs diff --git a/src/gui/styles/types/custom_palette.rs b/src/gui/styles/types/custom_palette.rs index 413f1633..03f8294c 100644 --- a/src/gui/styles/types/custom_palette.rs +++ b/src/gui/styles/types/custom_palette.rs @@ -1,8 +1,8 @@ use std::fmt; -use std::fs::{self, File}; +use std::fs::File; use std::hash::{Hash, Hasher}; -use std::io::{self, BufReader, Read}; -use std::path::{Path, PathBuf}; +use std::io::{BufReader, Read}; +use std::path::Path; use iced::Color; use serde::{de::Error as DeErrorTrait, Deserialize, Serialize}; @@ -64,32 +64,8 @@ impl CustomPalette { .read_to_string(&mut style_toml) .map_err(DeErrorTrait::custom)?; - // Deserialize it and store `path` into the resulting struct - // toml::de::from_str::(&style_toml).map(|mut style| { - // style.path = path; - // style - // }) - toml::de::from_str(&style_toml) } - - /// Load [CustomStyle]s from a directory. - /// - /// # Errors - /// [io::Error] is only returned if `dir` can't be read. A best effort is made to read any styles - /// present in the directory. - /// - /// Styles that cannot be read are ignored. - pub fn from_dir

(dir: P) -> Result, io::Error> - where - P: Into, - { - let iter = fs::read_dir(dir.into())?.filter_map(|entry| { - let entry = entry.ok()?.path(); - Self::from_file(entry.to_str()?).ok() - }); - Ok(iter) - } } impl Hash for CustomPalette { @@ -219,39 +195,20 @@ impl fmt::Display for ExtraStyles { #[cfg(test)] mod tests { - use super::{ - deserialize_from_path, serialize_to_path, CustomPalette, Palette, PaletteExtension, - }; - use crate::{translations::types::language::Language, StyleType}; + use super::{CustomPalette, Palette, PaletteExtension}; use iced::color; - use serde::{Deserialize, Serialize}; - use serde_test::{assert_tokens, Token}; - use std::collections::BTreeMap; - - // Convenience struct for testing - #[derive(Debug, PartialEq, Deserialize, Serialize)] - #[serde(transparent)] - struct StyleForTests( - #[serde( - deserialize_with = "deserialize_from_path", - serialize_with = "serialize_to_path" - )] - CustomPalette, - ); - // Test items - - // Replace with const format when it's stable - fn style_path() -> String { + fn style_path(name: &str) -> String { format!( - "{}/resources/themes/catppuccin_mocha.toml", - env!("CARGO_MANIFEST_DIR") + "{}/resources/themes/{}.toml", + env!("CARGO_MANIFEST_DIR"), + name ) } // NOTE: This has to be updated if `resources/themes/catppuccin_mocha.toml` changes - fn catppuccin_style() -> StyleForTests { - StyleForTests(CustomPalette { + fn catppuccin_style() -> CustomPalette { + CustomPalette { palette: Palette { primary: color!(30, 30, 46), secondary: color!(137, 180, 250), @@ -259,66 +216,23 @@ mod tests { outgoing: color!(245, 194, 231), text_headers: color!(17, 17, 27), text_body: color!(205, 214, 244), - round_borders: color!(180, 190, 254), - round_containers: color!(24, 24, 37), }, extension: PaletteExtension { starred: color!(249, 226, 175), - badge_alpha: 0.75, - color_mix_chart: 0.3, + round_borders_alpha: 0.1, + round_containers_alpha: 0.15, + chart_badge_alpha: 0.75, + nightly: true, }, - }) - } - - // Test that split deserialization works for `CustomStyle`. - // This is different than testing that `StyleType` properly deserializes. - #[test] - fn test_customstyle_split_de() { - let style_test = catppuccin_style(); - // This is only used for the test which requires an &'static str. - let path: &'static str = Box::leak(style_path().into_boxed_str()); - assert_tokens(&style_test, &[Token::String(path)]); + } } - // Ensure that StyleType itself still deserializes properly #[test] - fn test_styletype_unit_split_de() { - // Unit variant without a struct - assert_tokens( - &StyleType::DeepSea, - &[ - Token::Struct { - name: "StyleType", - len: 1, - }, - Token::Str("style"), - Token::Str("DeepSea"), - Token::StructEnd, - ], - ); - } + fn custompalette_from_file_de() -> Result<(), toml::de::Error> { + let style = catppuccin_style(); + let style_de = CustomPalette::from_file(style_path("catppuccin_mocha"))?; - // Test that StyleType::Custom successfully deserializes. - // Originally, StyleType::Custom did not ser/de correctly because of how TOML - // handles enums. - #[test] - fn test_styletype_custom_split_de() { - // CustomStyle - // This is only used for the test so leaking it is fine. - let path = &*Box::leak(style_path().into_boxed_str()); - assert_tokens( - &StyleType::Custom(catppuccin_style().0), - &[ - Token::Struct { - name: "StyleType", - len: 2, - }, - Token::Str("style"), - Token::Str("Custom"), - Token::Str("path"), - Token::Str(path), - Token::StructEnd, - ], - ); + assert_eq!(style, style_de); + Ok(()) } } diff --git a/src/gui/styles/types/custom_style.rs b/src/gui/styles/types/custom_style.rs deleted file mode 100644 index a0b11738..00000000 --- a/src/gui/styles/types/custom_style.rs +++ /dev/null @@ -1,122 +0,0 @@ -//! Custom Sniffnet color schemes. -//! Themes should be in TOML files with the following schema. -//! ```toml -//! name = "Theme's name" -//! -//! [description] -//! # Descriptions of the theme in any of Sniffnet's supported languages -//! # CODE = "DESC" -//! EN = "A fantastically dark theme!" -//! HU = "" -//! PL = "" -//! -//! # The palette is specified in RGB hexadecimal with an optional alpha -//! [palette] -//! primary = "#000000" -//! secondary = "#000000" -//! buttons = "#000000" -//! outgoing = "#000000" -//! text_headers = "#000000" -//! text_body = "#000000" -//! round_borders = "#000000" -//! round_containers = "#000000" -//! starred = "#000000" -//! -//! # floats for these two alpha values -//! badge_alpha = 0.9 -//! color_mix_chart = 0.3 -//! ``` - -use serde::{de::Error as DeErrorTrait, Deserialize, Deserializer, Serialize, Serializer}; -use std::{ - collections::BTreeMap, - fs::{self, File}, - io::{self, BufReader, Read}, - path::PathBuf, -}; - -use super::palette::{Palette, PaletteExtension}; -use crate::Language; - -/// Custom color scheme data including the palette, name, and location of the toml. -#[derive(Debug, PartialEq, Hash, Clone, Deserialize, Serialize)] -pub struct CustomStyle { - /// Display name of the color scheme. - /// This is the user facing color scheme name that may be displayed in the UI. - /// Ex. Catppuccin Mocha - pub name: String, - /// Internal or path name. - /// Ex. resources/catppuccin_mocha.toml - /// This field isn't deserialized because the theme shouldn't provide it. - /// However, the path is serialized into Sniffnet's config to reload the theme on launch. - #[serde(skip)] - pub path: String, - /// Short description of the color scheme - pub description: BTreeMap, - /// Color scheme's Sniffnet palette. - /// Should be an implementation of the scheme that is tuned to Sniffnet. - pub palette: CustomPalette, -} - -impl CustomStyle { - - - /// Return translated description or a default. - /// - /// Defaults to English is the language isn't implemented or "" if English is missing too. - /// - /// # Arguments - /// * `language` - Description language - pub fn description(&self, language: Language) -> &str { - self.description - .get(&language) - .map(|s| s.as_str()) - .unwrap_or_else(|| { - self.description - .get(&Language::EN) - .map(|s| s.as_str()) - .unwrap_or_default() - }) - } -} - -/// Base [Palette] and extension colors for [CustomStyle]. -// -// Clippy complains about deriving [Hash] with a manually written [PartialEq]. We manually implemented -// Hash for [Palette] and [PaletteExtension], so deriving Hash is convenient and the error is spurious. -#[allow(clippy::derived_hash_with_manual_eq)] -#[derive(Debug, Hash, Clone, PartialEq, Deserialize, Serialize)] -pub struct CustomPalette { - /// Base colors as used for the default sniffnet themes. - #[serde(flatten)] - pub base: Palette, - /// Extension colors such as the yellow used for favorites. - #[serde(flatten)] - pub extension: PaletteExtension, -} - -/// Deserialize [CustomStyle] from a file path. -/// -/// This is implemented by first deserializing a file path which in turn contains the style as TOML. -#[inline] -pub(super) fn deserialize_from_path<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let path = String::deserialize(deserializer)?; - CustomStyle::from_file(path).map_err(DeErrorTrait::custom) -} - -/// Serialize [CustomStyle]'s path. -/// -/// Themes aren't serialized because they're already located somewhere else (the TOML file from which it was loaded). -/// However, the theme's path must be serialized so that Sniffnet can reload it after the program is restarted. -#[inline] -pub(super) fn serialize_to_path(style: &CustomStyle, serializer: S) -> Result -where - S: Serializer, -{ - serializer.serialize_str(&style.path) -} - - From 09a99423a5142dfbe590dd06fd2101a864204099 Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Fri, 10 Nov 2023 10:28:15 +0100 Subject: [PATCH 25/29] fix README --- README.md | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) diff --git a/README.md b/README.md index 43aca0f0..568cc1b3 100644 --- a/README.md +++ b/README.md @@ -245,7 +245,7 @@ sudo sniffnet - 🌍 get information about the country of the remote hosts (IP geolocation) - ⭐ save your favorite network hosts - 🔉 set custom notifications to inform you when defined network events occur -- 🎨 choose the style that fits you the most from 4 different available themes plus custom theme support +- 🎨 choose the style that fits you the most from 12 different available themes, plus custom theme support - 🕵️ inspect each of your network connections in real time - 📁 save complete textual reports with detailed information for each network connection: * source and destination IP addresses @@ -416,25 +416,6 @@ Check the [required dependencies](#required-dependencies) section for instructio ### Rendering problems -<<<<<<< HEAD -In some cases, especially if you are running on an old architecture, the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) -may cause some problems that could prevent you from running Sniffnet.
-In this case, you can try building the application from the [`glow-renderer`](https://github.com/GyulyVGC/sniffnet/tree/glow-renderer) -branch, which uses the `glow` renderer. - -> **Note** -> -> View issues labeled with [`renderer`](https://github.com/GyulyVGC/sniffnet/issues?q=is%3Aissue+label%3Arenderer) to see how those problems have been solved by others. -||||||| ec3c96f -In some cases, especially if you are running on an old architecture, the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) -may cause some problems that could prevent you from running Sniffnet.
-In this case, you can try building the application from the [`glow-renderer`](https://github.com/GyulyVGC/sniffnet/tree/glow-renderer) -branch, which uses the `glow` renderer. - -> **Note** -> -> View issues labeled with [`renderer`](https://github.com/GyulyVGC/sniffnet/issues?q=is%3Aissue+label%3Arenderer) to see how those problems have been solved by others. -======= In some circumstances, especially if you are running on an old architecture or your graphical drivers are not up-to-date, the `wgpu` default renderer used by [iced](https://github.com/iced-rs/iced) may cause problems (country icons are completely black, or the interface glitches).
@@ -444,7 +425,6 @@ which is based on `tiny-skia`, a CPU-only software renderer that should work pro [macOS](https://github.com/GyulyVGC/sniffnet/suites/14909529200/artifacts/849640694) | [Linux DEB](https://github.com/GyulyVGC/sniffnet/suites/14909529200/artifacts/849640693) | [Linux RPM](https://github.com/GyulyVGC/sniffnet/suites/14909529200/artifacts/849640696) ->>>>>>> upstream/advanced-settings ### ***In any case don't hesitate to [open an issue](https://github.com/GyulyVGC/sniffnet/issues), and I will do my best to help you!*** From 46885a721a13d6daa0fc5b3fad4645d27bda5984 Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Fri, 10 Nov 2023 11:18:28 +0100 Subject: [PATCH 26/29] fix warnings and clippy lints --- resources/themes/catppuccin_frappe.toml | 12 -- resources/themes/catppuccin_latte.toml | 12 -- resources/themes/catppuccin_macchiato.toml | 12 -- resources/themes/dracula.toml | 11 -- src/configs/types/config_advanced_settings.rs | 10 +- src/gui/pages/inspect_page.rs | 3 +- src/gui/pages/settings_advanced_page.rs | 29 ++-- src/gui/styles/custom_themes/dracula.rs | 4 +- src/gui/styles/types/color_remote.rs | 62 +++---- src/gui/styles/types/custom_palette.rs | 15 +- src/gui/styles/types/palette.rs | 3 +- src/gui/types/sniffer.rs | 6 +- src/main.rs | 6 +- src/networking/manage_packets.rs | 3 +- src/notifications/types/notifications.rs | 4 +- src/secondary_threads/write_report_file.rs | 154 +++++++++--------- 16 files changed, 154 insertions(+), 192 deletions(-) delete mode 100644 resources/themes/catppuccin_frappe.toml delete mode 100644 resources/themes/catppuccin_latte.toml delete mode 100644 resources/themes/catppuccin_macchiato.toml delete mode 100644 resources/themes/dracula.toml diff --git a/resources/themes/catppuccin_frappe.toml b/resources/themes/catppuccin_frappe.toml deleted file mode 100644 index 64d026a4..00000000 --- a/resources/themes/catppuccin_frappe.toml +++ /dev/null @@ -1,12 +0,0 @@ -# https://github.com/catppuccin/catppuccin -primary = "#303446" # Base -secondary = "#a6d189" # Green -buttons = "#414559" # Surface0 -outgoing = "#f4b8e4" # Pink -text_headers = "#232634" # Crust -text_body = "#c6d0f5" # Text -starred = "#e5c890" # Yellow -round_borders_alpha = 0.1 -round_containers_alpha = 0.04 -chart_badge_alpha = 0.55 -nightly = true diff --git a/resources/themes/catppuccin_latte.toml b/resources/themes/catppuccin_latte.toml deleted file mode 100644 index 566e1973..00000000 --- a/resources/themes/catppuccin_latte.toml +++ /dev/null @@ -1,12 +0,0 @@ -# https://github.com/catppuccin/catppuccin" -primary = "#eff1f5" # Base -secondary = "#1e66f5" # Blue -buttons = "#ccd0da" # Surface0 -outgoing = "#ea76cb" # Pink -text_headers = "#dce0e8" # Crust -text_body = "#4c4f69" # Text -starred = "#df8e1d" # Yellow -round_borders_alpha = 0.15 -round_containers_alpha = 0.25 -chart_badge_alpha = 0.75 -nightly = false diff --git a/resources/themes/catppuccin_macchiato.toml b/resources/themes/catppuccin_macchiato.toml deleted file mode 100644 index 7c31f684..00000000 --- a/resources/themes/catppuccin_macchiato.toml +++ /dev/null @@ -1,12 +0,0 @@ -# https://github.com/catppuccin/catppuccin -primary = "#24273a" # Base -secondary = "#f5bde6" # Pink -buttons = "#363a4f" # Surface0 -outgoing = "#c6a0f6" # Mauve -text_headers = "#181926" # Crust -text_body = "#cad3f5" # Text -starred = "#eed49f" # Yellow -round_borders_alpha = 0.1 -round_containers_alpha = 0.15 -chart_badge_alpha = 0.75 -nightly = true diff --git a/resources/themes/dracula.toml b/resources/themes/dracula.toml deleted file mode 100644 index ebc529bc..00000000 --- a/resources/themes/dracula.toml +++ /dev/null @@ -1,11 +0,0 @@ -primary = "#44475a" # Current line -secondary = "#ff79c6" # Pink -buttons = "#6272a4" # Comment -outgoing = "#8be9fd" # Cyan -text_headers = "#282a36" # Background -text_body = "#f8f8f2" # Foreground -starred = "#f1fa8cb2" # Yellow -round_borders_alpha = 0.1 -round_containers_alpha = 0.04 -chart_badge_alpha = 0.15 -nightly = true diff --git a/src/configs/types/config_advanced_settings.rs b/src/configs/types/config_advanced_settings.rs index 7f66fb59..181c9d6f 100644 --- a/src/configs/types/config_advanced_settings.rs +++ b/src/configs/types/config_advanced_settings.rs @@ -1,17 +1,19 @@ //! Module defining the `ConfigAdvancedSettings` struct, which allows to save and reload //! the application advanced settings. -use crate::utils::formatted_strings::get_default_report_directory; -use serde::{Deserialize, Serialize}; use std::path::PathBuf; +use serde::{Deserialize, Serialize}; + +use crate::utils::formatted_strings::get_default_report_directory; + #[derive(Serialize, Deserialize, Clone, PartialEq)] pub struct ConfigAdvancedSettings { pub scale_factor: f64, pub mmdb_country: String, pub mmdb_asn: String, pub output_path: PathBuf, - pub style_path: Option + pub style_path: Option, } impl ConfigAdvancedSettings { @@ -43,7 +45,7 @@ impl Default for ConfigAdvancedSettings { mmdb_country: String::new(), mmdb_asn: String::new(), output_path: get_default_report_directory(), - style_path: None + style_path: None, } } } diff --git a/src/gui/pages/inspect_page.rs b/src/gui/pages/inspect_page.rs index e152ba81..5687a122 100644 --- a/src/gui/pages/inspect_page.rs +++ b/src/gui/pages/inspect_page.rs @@ -1,3 +1,5 @@ +use std::path::Path; + use iced::alignment::{Horizontal, Vertical}; use iced::widget::scrollable::Direction; use iced::widget::tooltip::Position; @@ -6,7 +8,6 @@ use iced::widget::{ lazy, Button, Checkbox, Column, Container, PickList, Row, Scrollable, Text, TextInput, Tooltip, }; use iced::{alignment, Alignment, Font, Length, Renderer}; -use std::path::Path; use crate::gui::components::tab::get_pages_tabs; use crate::gui::components::types::my_modal::MyModal; diff --git a/src/gui/pages/settings_advanced_page.rs b/src/gui/pages/settings_advanced_page.rs index cd68fb7f..db4df718 100644 --- a/src/gui/pages/settings_advanced_page.rs +++ b/src/gui/pages/settings_advanced_page.rs @@ -1,3 +1,15 @@ +use std::path::{Path, PathBuf}; +use std::sync::Arc; + +use iced::advanced::widget::Text; +use iced::alignment::{Horizontal, Vertical}; +use iced::widget::tooltip::Position; +use iced::widget::{ + button, horizontal_space, vertical_space, Column, Container, Row, Slider, TextInput, Tooltip, +}; +use iced::Length::Fixed; +use iced::{Alignment, Font, Length, Renderer}; + use crate::gui::components::tab::get_settings_tabs; use crate::gui::pages::settings_notifications_page::settings_header; use crate::gui::pages::types::settings_page::SettingsPage; @@ -16,16 +28,6 @@ use crate::utils::asn::MmdbReader; use crate::utils::formatted_strings::get_default_report_directory; use crate::utils::types::icon::Icon; use crate::{ConfigAdvancedSettings, Language, Sniffer, Status, StyleType}; -use iced::advanced::widget::Text; -use iced::alignment::{Horizontal, Vertical}; -use iced::widget::tooltip::Position; -use iced::widget::{ - button, horizontal_space, vertical_space, Column, Container, Row, Slider, TextInput, Tooltip, -}; -use iced::Length::Fixed; -use iced::{Alignment, Font, Length, Renderer}; -use std::path::{Path, PathBuf}; -use std::sync::Arc; pub fn settings_advanced_page(sniffer: &Sniffer) -> Container> { let font = get_font(sniffer.style); @@ -171,11 +173,8 @@ fn report_path_setting( let default_directory = &get_default_report_directory().to_string_lossy().to_string(); path.pop(); let custom_directory = &path.to_string_lossy().to_string(); - let is_error = if custom_directory.is_empty() { - false - } else { - true - }; + // to be updated.........!!! + let is_error = !custom_directory.is_empty(); let mut input = TextInput::new(default_directory, custom_directory) .padding([0, 5]) diff --git a/src/gui/styles/custom_themes/dracula.rs b/src/gui/styles/custom_themes/dracula.rs index 87b9e4af..aef2b3b3 100644 --- a/src/gui/styles/custom_themes/dracula.rs +++ b/src/gui/styles/custom_themes/dracula.rs @@ -23,7 +23,7 @@ pub(in crate::gui::styles) fn dracula_dark() -> CustomPalette { round_borders_alpha: 0.1, round_containers_alpha: 0.04, chart_badge_alpha: 0.15, - nightly: true + nightly: true, }, } } @@ -44,7 +44,7 @@ pub(in crate::gui::styles) fn dracula_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.45, round_containers_alpha: 0.25, - nightly: true + nightly: true, }, } } diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index b36afc8c..6756af69 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -1,16 +1,17 @@ -//! Remote implemention of [serde::Deserialize] and [serde::Serialize] for [iced::Color]. +//! Remote implemention of [`serde::Deserialize`] and [`serde::Serialize`] for [`iced::Color`]. //! //! This implementation deserializes hexadecimal RGB(A) as string to float RGB(A) and back. //! NOTE: The alpha channel is optional and defaults to #ff or 1.0. //! `#ffffffff` deserializes to `1.0`, `1.0`, `1.0`, `1.0`. //! `1.0`, `1.0`, `1.0`, `1.0` serializes to #ffffffff +use std::hash::{Hash, Hasher}; + use iced::Color; use serde::{ de::{Error as DeErrorTrait, Unexpected}, - Deserialize, Deserializer, Serializer, + Deserialize, Deserializer, }; -use std::hash::{Hash, Hasher}; // #aabbcc is seven bytes long const HEX_STR_BASE_LEN: usize = 7; @@ -52,7 +53,7 @@ where .and_then(|s| { u8::from_str_radix(s, 16) .map_err(DeErrorTrait::custom) - .map(|rgb| rgb as f32 / 255.0) + .map(|rgb| f32::from(rgb) / 255.0) }) }) .collect::, _>>()?; @@ -73,7 +74,7 @@ where } } -/// Hash delegate for [iced::Color] that hashes RGBA in lieu of floats. +/// Hash delegate for [`iced::Color`] that hashes RGBA in lieu of floats. #[inline] pub(super) fn color_hash(color: Color, state: &mut H) { // Hash isn't implemented for floats, so I hash the color as RGBA instead. @@ -81,36 +82,37 @@ pub(super) fn color_hash(color: Color, state: &mut H) { color.hash(state); } -/// Serialize [iced::Color] as a hex string. -#[inline] -pub(super) fn serialize_color(color: &Color, serializer: S) -> Result -where - S: Serializer, -{ - // iced::Color to [u8; 4] - let color = color.into_rgba8(); - - // [u8; 4] to hex string, precluding the alpha if it's 0xff. - let hex_color = if color[3] != 255 { - format!( - "#{:02x}{:02x}{:02x}{:02x}", - color[0], color[1], color[2], color[3] - ) - } else { - format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]) - }; - - // Serialize the hex string - serializer.serialize_str(&hex_color) -} - #[cfg(test)] mod tests { - use super::{deserialize_color, serialize_color}; use iced::Color; - use serde::{Deserialize, Serialize}; + use serde::{Deserialize, Serialize, Serializer}; use serde_test::{assert_de_tokens_error, assert_tokens, Token}; + use super::deserialize_color; + + /// Serialize [`iced::Color`] as a hex string. + #[inline] + fn serialize_color(color: &Color, serializer: S) -> Result + where + S: Serializer, + { + // iced::Color to [u8; 4] + let color = color.into_rgba8(); + + // [u8; 4] to hex string, precluding the alpha if it's 0xff. + let hex_color = if color[3] != 255 { + format!( + "#{:02x}{:02x}{:02x}{:02x}", + color[0], color[1], color[2], color[3] + ) + } else { + format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]) + }; + + // Serialize the hex string + serializer.serialize_str(&hex_color) + } + // https://github.com/catppuccin/catppuccin const CATPPUCCIN_PINK_HEX: &str = "#f5c2e7"; const CATPPUCCIN_PINK: Color = Color { diff --git a/src/gui/styles/types/custom_palette.rs b/src/gui/styles/types/custom_palette.rs index 03f8294c..e8c54e8a 100644 --- a/src/gui/styles/types/custom_palette.rs +++ b/src/gui/styles/types/custom_palette.rs @@ -7,10 +7,11 @@ use std::path::Path; use iced::Color; use serde::{de::Error as DeErrorTrait, Deserialize, Serialize}; -use super::color_remote::{color_hash, deserialize_color}; use crate::gui::styles::custom_themes::{dracula, gruvbox, nord, solarized}; use crate::gui::styles::types::palette::Palette; +use super::color_remote::{color_hash, deserialize_color}; + const FLOAT_PRECISION: f32 = 10000.0; /// Custom style with any relevant metadata @@ -45,7 +46,7 @@ pub struct PaletteExtension { } impl CustomPalette { - /// Deserialize [CustomPalette] from `path`. + /// Deserialize [`CustomPalette`] from `path`. /// /// # Arguments /// * `path` - Path to a UTF-8 encoded file containing a custom style as TOML. @@ -88,7 +89,7 @@ impl Hash for CustomPalette { color_hash(*text_headers, state); color_hash(*text_body, state); - extension.hash(state) + extension.hash(state); } } @@ -103,8 +104,11 @@ impl Hash for PaletteExtension { } = self; color_hash(*starred, state); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] ((*chart_badge_alpha * FLOAT_PRECISION).trunc() as u32).hash(state); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] ((*round_borders_alpha * FLOAT_PRECISION).trunc() as u32).hash(state); + #[allow(clippy::cast_possible_truncation, clippy::cast_sign_loss)] ((*round_containers_alpha * FLOAT_PRECISION).trunc() as u32).hash(state); } } @@ -188,16 +192,17 @@ impl fmt::Display for ExtraStyles { ExtraStyles::SolarizedLight => write!(f, "Solarized (Day)"), ExtraStyles::SolarizedDark => write!(f, "Solarized (Night)"), // Custom style names aren't used anywhere so this shouldn't be reached - _ => unreachable!(), + ExtraStyles::CustomToml(_) => unreachable!(), } } } #[cfg(test)] mod tests { - use super::{CustomPalette, Palette, PaletteExtension}; use iced::color; + use super::{CustomPalette, Palette, PaletteExtension}; + fn style_path(name: &str) -> String { format!( "{}/resources/themes/{}.toml", diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index ee3ec15f..77b41746 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -4,12 +4,13 @@ use iced::Color; use plotters::style::RGBColor; use serde::Deserialize; -use super::color_remote::deserialize_color; use crate::gui::styles::style_constants::{ DAY_STYLE, DEEP_SEA_STYLE, MON_AMOUR_STYLE, NIGHT_STYLE, }; use crate::StyleType; +use super::color_remote::deserialize_color; + /// Set of colors to apply to GUI /// /// Best practices: diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index 31afd1f8..1f2250e3 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -182,10 +182,10 @@ impl Sniffer { self.traffic_chart.change_style(self.style); } Message::LoadStyle(path) => { - self.advanced_settings.style_path = if !path.is_empty() { - Some(path.into()) - } else { + self.advanced_settings.style_path = if path.is_empty() { None + } else { + Some(path.into()) }; if let Some(path) = self.advanced_settings.style_path.as_deref() { diff --git a/src/main.rs b/src/main.rs index 2cb8bd53..37aff457 100644 --- a/src/main.rs +++ b/src/main.rs @@ -9,9 +9,6 @@ use std::{panic, process, thread}; use iced::window::PlatformSpecific; use iced::{window, Application, Font, Settings}; -use crate::configs::types::config_advanced_settings::ConfigAdvancedSettings; -use crate::configs::types::config_window::{ConfigWindow, ToPosition}; -use crate::configs::types::configs::Configs; use chart::types::chart_type::ChartType; use chart::types::traffic_chart::TrafficChart; use cli::parse_cli_args; @@ -33,6 +30,9 @@ use report::types::report_sort_type::ReportSortType; use translations::types::language::Language; use utils::formatted_strings::print_cli_welcome_message; +use crate::configs::types::config_advanced_settings::ConfigAdvancedSettings; +use crate::configs::types::config_window::{ConfigWindow, ToPosition}; +use crate::configs::types::configs::Configs; use crate::secondary_threads::check_updates::set_newer_release_status; mod chart; diff --git a/src/networking/manage_packets.rs b/src/networking/manage_packets.rs index 5fdf002a..20cc5a95 100644 --- a/src/networking/manage_packets.rs +++ b/src/networking/manage_packets.rs @@ -9,7 +9,6 @@ use pcap::{Active, Address, Capture, Device}; use crate::countries::country_utils::get_country; use crate::networking::types::address_port_pair::AddressPortPair; use crate::networking::types::app_protocol::from_port_to_application_protocol; -use crate::networking::types::data_info::DataInfo; use crate::networking::types::data_info_host::DataInfoHost; use crate::networking::types::filters::Filters; use crate::networking::types::host::Host; @@ -284,7 +283,7 @@ pub fn reverse_dns_lookup( let other_data = info_traffic_lock .addresses_waiting_resolution .remove(&address_to_lookup) - .unwrap_or(DataInfo::default()); + .unwrap_or_default(); // insert the newly resolved host in the collections, with the data it exchanged so far info_traffic_lock .addresses_resolved diff --git a/src/notifications/types/notifications.rs b/src/notifications/types/notifications.rs index e3eff629..6d6f6b41 100644 --- a/src/notifications/types/notifications.rs +++ b/src/notifications/types/notifications.rs @@ -58,7 +58,7 @@ impl Default for PacketsNotification { impl PacketsNotification { /// Arbitrary string constructor. Will fallback values to existing notification if set, default() otherwise pub fn from(value: &str, existing: Option) -> Self { - let default = existing.unwrap_or(Self::default()); + let default = existing.unwrap_or_default(); let new_threshold = if value.is_empty() { 0 @@ -99,7 +99,7 @@ impl Default for BytesNotification { impl BytesNotification { /// Arbitrary string constructor. Will fallback values to existing notification if set, default() otherwise pub fn from(value: &str, existing: Option) -> Self { - let default = existing.unwrap_or(Self::default()); + let default = existing.unwrap_or_default(); let mut byte_multiple_inserted = ByteMultiple::B; let new_threshold = if value.is_empty() { diff --git a/src/secondary_threads/write_report_file.rs b/src/secondary_threads/write_report_file.rs index ad23e979..e65f9bbf 100644 --- a/src/secondary_threads/write_report_file.rs +++ b/src/secondary_threads/write_report_file.rs @@ -1,77 +1,77 @@ -//! Module containing functions executed by the thread in charge of updating the output report every 1 second - -use std::collections::HashSet; -use std::fs::File; -use std::io::{BufWriter, Seek, SeekFrom, Write}; -use std::sync::{Arc, Condvar, Mutex}; -use std::thread; -use std::time::Duration; - -use crate::gui::types::status::Status; -use crate::utils::formatted_strings::get_default_report_directory; -use crate::InfoTraffic; - -/// The calling thread enters in a loop in which it sleeps for 1 second and then -/// updates the output report containing detailed traffic information -pub fn sleep_and_write_report_loop( - current_capture_id: &Arc>, - info_traffic_mutex: &Arc>, - status_pair: &Arc<(Mutex, Condvar)>, -) { - let cvar = &status_pair.1; - - let path_report = get_default_report_directory(); - - let mut capture_id = *current_capture_id.lock().unwrap(); - - let mut output = - BufWriter::new(File::create(path_report.clone()).expect("Error creating output file\n\r")); - writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); - writeln!(output, "| Src IP address | Src port | Dst IP address | Dst port | Layer 4 | Layer 7 | Packets | Bytes | Initial timestamp | Final timestamp |").expect("Error writing output file\n\r"); - writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); - - loop { - // sleep 1 second - thread::sleep(Duration::from_secs(1)); - - let current_capture_id_lock = current_capture_id.lock().unwrap(); - if *current_capture_id_lock != capture_id { - capture_id = *current_capture_id_lock; - output = BufWriter::new( - File::create(path_report.clone()).expect("Error creating output file\n\r"), - ); - writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); - writeln!(output, "| Src IP address | Src port | Dst IP address | Dst port | Layer 4 | Layer 7 | Packets | Bytes | Initial timestamp | Final timestamp |").expect("Error writing output file\n\r"); - writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); - } - drop(current_capture_id_lock); - - let mut status = status_pair.0.lock().expect("Error acquiring mutex\n\r"); - - if *status == Status::Running { - drop(status); - - let mut info_traffic = info_traffic_mutex - .lock() - .expect("Error acquiring mutex\n\r"); - - for index in &info_traffic.addresses_last_interval { - let key_val = info_traffic.map.get_index(*index).unwrap(); - let seek_pos = 166 * 3 + 206 * (*index) as u64; - output.seek(SeekFrom::Start(seek_pos)).unwrap(); - writeln!(output, "{}{}", key_val.0, key_val.1) - .expect("Error writing output file\n\r"); - } - info_traffic.addresses_last_interval = HashSet::new(); // empty set - - drop(info_traffic); - - output.flush().expect("Error writing output file\n\r"); - } else { - //status is Init - while *status == Status::Init { - status = cvar.wait(status).expect("Error acquiring mutex\n\r"); - } - } - } -} +// //! Module containing functions executed by the thread in charge of updating the output report every 1 second +// +// use std::collections::HashSet; +// use std::fs::File; +// use std::io::{BufWriter, Seek, SeekFrom, Write}; +// use std::sync::{Arc, Condvar, Mutex}; +// use std::thread; +// use std::time::Duration; +// +// use crate::gui::types::status::Status; +// use crate::utils::formatted_strings::get_default_report_directory; +// use crate::InfoTraffic; +// +// /// The calling thread enters in a loop in which it sleeps for 1 second and then +// /// updates the output report containing detailed traffic information +// pub fn sleep_and_write_report_loop( +// current_capture_id: &Arc>, +// info_traffic_mutex: &Arc>, +// status_pair: &Arc<(Mutex, Condvar)>, +// ) { +// let cvar = &status_pair.1; +// +// let path_report = get_default_report_directory(); +// +// let mut capture_id = *current_capture_id.lock().unwrap(); +// +// let mut output = +// BufWriter::new(File::create(path_report.clone()).expect("Error creating output file\n\r")); +// writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); +// writeln!(output, "| Src IP address | Src port | Dst IP address | Dst port | Layer 4 | Layer 7 | Packets | Bytes | Initial timestamp | Final timestamp |").expect("Error writing output file\n\r"); +// writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); +// +// loop { +// // sleep 1 second +// thread::sleep(Duration::from_secs(1)); +// +// let current_capture_id_lock = current_capture_id.lock().unwrap(); +// if *current_capture_id_lock != capture_id { +// capture_id = *current_capture_id_lock; +// output = BufWriter::new( +// File::create(path_report.clone()).expect("Error creating output file\n\r"), +// ); +// writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); +// writeln!(output, "| Src IP address | Src port | Dst IP address | Dst port | Layer 4 | Layer 7 | Packets | Bytes | Initial timestamp | Final timestamp |").expect("Error writing output file\n\r"); +// writeln!(output, "---------------------------------------------------------------------------------------------------------------------------------------------------------------------").expect("Error writing output file\n\r"); +// } +// drop(current_capture_id_lock); +// +// let mut status = status_pair.0.lock().expect("Error acquiring mutex\n\r"); +// +// if *status == Status::Running { +// drop(status); +// +// let mut info_traffic = info_traffic_mutex +// .lock() +// .expect("Error acquiring mutex\n\r"); +// +// for index in &info_traffic.addresses_last_interval { +// let key_val = info_traffic.map.get_index(*index).unwrap(); +// let seek_pos = 166 * 3 + 206 * (*index) as u64; +// output.seek(SeekFrom::Start(seek_pos)).unwrap(); +// writeln!(output, "{}{}", key_val.0, key_val.1) +// .expect("Error writing output file\n\r"); +// } +// info_traffic.addresses_last_interval = HashSet::new(); // empty set +// +// drop(info_traffic); +// +// output.flush().expect("Error writing output file\n\r"); +// } else { +// //status is Init +// while *status == Status::Init { +// status = cvar.wait(status).expect("Error acquiring mutex\n\r"); +// } +// } +// } +// } From 8f622041f4c06e35b81c3cc5cee8730ec0e08027 Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Fri, 10 Nov 2023 11:28:36 +0100 Subject: [PATCH 27/29] fix wrong nightly parameter for light themes --- src/gui/styles/custom_themes/dracula.rs | 2 +- src/gui/styles/custom_themes/gruvbox.rs | 2 +- src/gui/styles/custom_themes/nord.rs | 2 +- src/gui/styles/custom_themes/solarized.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/styles/custom_themes/dracula.rs b/src/gui/styles/custom_themes/dracula.rs index aef2b3b3..58a9cef6 100644 --- a/src/gui/styles/custom_themes/dracula.rs +++ b/src/gui/styles/custom_themes/dracula.rs @@ -44,7 +44,7 @@ pub(in crate::gui::styles) fn dracula_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.45, round_containers_alpha: 0.25, - nightly: true, + nightly: false, }, } } diff --git a/src/gui/styles/custom_themes/gruvbox.rs b/src/gui/styles/custom_themes/gruvbox.rs index 803d763f..7f37cc90 100644 --- a/src/gui/styles/custom_themes/gruvbox.rs +++ b/src/gui/styles/custom_themes/gruvbox.rs @@ -45,7 +45,7 @@ pub(in crate::gui::styles) fn gruvbox_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.45, round_containers_alpha: 0.2, - nightly: true, + nightly: false, }, } } diff --git a/src/gui/styles/custom_themes/nord.rs b/src/gui/styles/custom_themes/nord.rs index af4cac08..3386f78c 100644 --- a/src/gui/styles/custom_themes/nord.rs +++ b/src/gui/styles/custom_themes/nord.rs @@ -42,7 +42,7 @@ pub(in crate::gui::styles) fn nord_light() -> CustomPalette { chart_badge_alpha: 0.6, round_borders_alpha: 0.35, round_containers_alpha: 0.15, - nightly: true, + nightly: false, }, } } diff --git a/src/gui/styles/custom_themes/solarized.rs b/src/gui/styles/custom_themes/solarized.rs index 24125541..d877a7b8 100644 --- a/src/gui/styles/custom_themes/solarized.rs +++ b/src/gui/styles/custom_themes/solarized.rs @@ -23,7 +23,7 @@ pub(in crate::gui::styles) fn solarized_light() -> CustomPalette { chart_badge_alpha: 0.75, round_borders_alpha: 0.35, round_containers_alpha: 0.15, - nightly: true, + nightly: false, }, } } From ebb02529e45b1ac8bd2fe53c574aeef516c56845 Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Fri, 10 Nov 2023 11:35:23 +0100 Subject: [PATCH 28/29] undo derive Ord and PartialOrd for Language --- src/translations/types/language.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations/types/language.rs b/src/translations/types/language.rs index d46d6b8e..d4d0eb08 100644 --- a/src/translations/types/language.rs +++ b/src/translations/types/language.rs @@ -9,7 +9,7 @@ use crate::countries::flags_pictures::{ use crate::StyleType; /// This enum defines the available languages. -#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash, PartialOrd, Ord)] +#[derive(PartialEq, Eq, Clone, Copy, Debug, Serialize, Deserialize, Hash)] pub enum Language { /// English (default language). EN, From 93ead049649ea12bacd666c7ac442026782845f3 Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Sun, 12 Nov 2023 22:34:19 +0100 Subject: [PATCH 29/29] fix: consistency in loading/storing styles --- README.md | 30 +++++----- resources/themes/catppuccin_mocha.toml | 28 +++++---- src/configs/types/config_advanced_settings.rs | 4 +- src/configs/types/configs.rs | 18 +----- src/gui/pages/settings_advanced_page.rs | 59 +++++++++---------- src/gui/styles/types/color_remote.rs | 52 ++++++++-------- src/gui/styles/types/custom_palette.rs | 18 +++--- src/gui/styles/types/palette.rs | 36 ++++++++--- src/gui/types/sniffer.rs | 19 ++---- src/translations/translations_3.rs | 8 +++ 10 files changed, 139 insertions(+), 133 deletions(-) diff --git a/README.md b/README.md index 568cc1b3..ca107c11 100644 --- a/README.md +++ b/README.md @@ -381,21 +381,21 @@ The currently usable hotkeys are reported in the following. The TOML must follow this format: ```toml - # Color palettes are in RGBA hexadecimal where the alpha is optional. - primary = "#1e1e2e" # Base - secondary = "#89b4fa" # Blue - buttons = "#313244" # Surface0 - outgoing = "#f5c2e7" # Pink - text_headers = "#11111b" # Crust - text_body = "#cdd6f4" # Text - starred = "#f9e2af" # Yellow - - # Alpha channels are floats within [0.0, 1.0] - round_borders_alpha = 0.1 - round_containers_alpha = 0.15 - chart_badge_alpha = 0.75 - - # Night or dark themes should be specified here + # Colors are in RGB/RGBA hexadecimal. + primary = "#1e1e2e" # Background + secondary = "#89b4fa" # Headers / incoming connections + buttons = "#313244" # Buttons + outgoing = "#f5c2e7" # Outgoing connections + text_headers = "#11111b" # Text headers + text_body = "#cdd6f4" # Text body + starred = "#f9e2afaa" # Favorites + + # The following parameters are in the range [0.0, 1.0]. + round_borders_alpha = 0.3 # Borders opacity + round_containers_alpha = 0.15 # Containers opacity + chart_badge_alpha = 0.2 # Chart opacity + + # Set to true if the theme is dark, false if it's light. nightly = true ``` diff --git a/resources/themes/catppuccin_mocha.toml b/resources/themes/catppuccin_mocha.toml index 488af0b0..1b7cc74f 100644 --- a/resources/themes/catppuccin_mocha.toml +++ b/resources/themes/catppuccin_mocha.toml @@ -1,12 +1,16 @@ -# https://github.com/catppuccin/catppuccin -primary = "#1e1e2e" # Base -secondary = "#89b4fa" # Blue -buttons = "#313244" # Surface0 -outgoing = "#f5c2e7" # Pink -text_headers = "#11111b" # Crust -text_body = "#cdd6f4" # Text -starred = "#f9e2af" # Yellow -round_borders_alpha = 0.1 -round_containers_alpha = 0.15 -chart_badge_alpha = 0.75 -nightly = true +# Colors are in RGB/RGBA hexadecimal. +primary = "#1e1e2e" # Background +secondary = "#89b4fa" # Headers / incoming connections +buttons = "#313244" # Buttons +outgoing = "#f5c2e7" # Outgoing connections +text_headers = "#11111b" # Text headers +text_body = "#cdd6f4" # Text body +starred = "#f9e2afaa" # Favorites + +# The following parameters are in the range [0.0, 1.0]. +round_borders_alpha = 0.3 # Borders opacity +round_containers_alpha = 0.15 # Containers opacity +chart_badge_alpha = 0.2 # Chart opacity + +# Set to true if the theme is dark, false if it's light. +nightly = true \ No newline at end of file diff --git a/src/configs/types/config_advanced_settings.rs b/src/configs/types/config_advanced_settings.rs index 181c9d6f..fd175bcc 100644 --- a/src/configs/types/config_advanced_settings.rs +++ b/src/configs/types/config_advanced_settings.rs @@ -13,7 +13,7 @@ pub struct ConfigAdvancedSettings { pub mmdb_country: String, pub mmdb_asn: String, pub output_path: PathBuf, - pub style_path: Option, + pub style_path: PathBuf, } impl ConfigAdvancedSettings { @@ -45,7 +45,7 @@ impl Default for ConfigAdvancedSettings { mmdb_country: String::new(), mmdb_asn: String::new(), output_path: get_default_report_directory(), - style_path: None, + style_path: PathBuf::new(), } } } diff --git a/src/configs/types/configs.rs b/src/configs/types/configs.rs index dc134e15..b53c6097 100644 --- a/src/configs/types/configs.rs +++ b/src/configs/types/configs.rs @@ -1,5 +1,3 @@ -use crate::gui::styles::types::custom_palette::{CustomPalette, ExtraStyles}; -use crate::gui::styles::types::style_type::StyleType; use crate::{ConfigAdvancedSettings, ConfigDevice, ConfigSettings, ConfigWindow}; #[derive(Default)] @@ -12,22 +10,10 @@ pub struct Configs { impl Configs { pub fn load() -> Self { - let mut settings = ConfigSettings::load(); - let advanced_settings = ConfigAdvancedSettings::load(); - - if let Some(style_path) = &advanced_settings.style_path { - // Don't clobber the previously set style if the path is broken - if let Ok(style) = CustomPalette::from_file(style_path) - .map(|palette| StyleType::Custom(ExtraStyles::CustomToml(palette))) - { - settings.style = style; - } - } - Configs { - settings, + settings: ConfigSettings::load(), device: ConfigDevice::load(), - advanced_settings, + advanced_settings: ConfigAdvancedSettings::load(), window: ConfigWindow::load(), } } diff --git a/src/gui/pages/settings_advanced_page.rs b/src/gui/pages/settings_advanced_page.rs index db4df718..2e5940bb 100644 --- a/src/gui/pages/settings_advanced_page.rs +++ b/src/gui/pages/settings_advanced_page.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::PathBuf; use std::sync::Arc; use iced::advanced::widget::Text; @@ -17,12 +17,13 @@ use crate::gui::styles::container::ContainerType; use crate::gui::styles::style_constants::{get_font, get_font_headers, FONT_SIZE_SUBTITLE}; use crate::gui::styles::text::TextType; use crate::gui::styles::text_input::TextInputType; +use crate::gui::styles::types::custom_palette::CustomPalette; use crate::gui::types::message::Message; use crate::translations::translations_2::country_translation; use crate::translations::translations_3::{ - advanced_settings_translation, file_path_translation, info_mmdb_paths_translation, - mmdb_paths_translation, params_not_editable_translation, restore_defaults_translation, - scale_factor_translation, + advanced_settings_translation, custom_style_translation, file_path_translation, + info_mmdb_paths_translation, mmdb_paths_translation, params_not_editable_translation, + restore_defaults_translation, scale_factor_translation, }; use crate::utils::asn::MmdbReader; use crate::utils::formatted_strings::get_default_report_directory; @@ -60,6 +61,11 @@ pub fn settings_advanced_page(sniffer: &Sniffer) -> Container Container, - caption: &str, + custom_path: &PathBuf, ) -> Row<'static, Message, Renderer> { - let is_error = custom_path - .is_some_and(|path| path.extension().map_or(true, |ext| ext != "toml") || !path.exists()); + let path_str = &custom_path.to_string_lossy().to_string(); - let mut input = TextInput::new( - "-", - &custom_path.map(Path::to_string_lossy).unwrap_or_default(), - ) - .padding([0, 5]) - .font(font) - .width(Length::Fixed(200.0)) - .style(if is_error { - TextInputType::Error + let is_error = if path_str.is_empty() { + false } else { - TextInputType::Standard - }); + CustomPalette::from_file(custom_path).is_err() + }; - if is_editable { - input = input.on_input(Message::LoadStyle); - } + let input = TextInput::new("-", path_str) + .on_input(Message::LoadStyle) + .on_submit(Message::LoadStyle(path_str.clone())) + .padding([0, 5]) + .font(font) + .width(Length::Fixed(200.0)) + .style(if is_error { + TextInputType::Error + } else { + TextInputType::Standard + }); Row::new() .spacing(5) - .push(Text::new(format!("{caption}:")).font(font)) + .push(Text::new(format!("{}:", custom_style_translation(language))).font(font)) .push(input) } diff --git a/src/gui/styles/types/color_remote.rs b/src/gui/styles/types/color_remote.rs index 6756af69..32073d3d 100644 --- a/src/gui/styles/types/color_remote.rs +++ b/src/gui/styles/types/color_remote.rs @@ -10,7 +10,7 @@ use std::hash::{Hash, Hasher}; use iced::Color; use serde::{ de::{Error as DeErrorTrait, Unexpected}, - Deserialize, Deserializer, + Deserialize, Deserializer, Serializer, }; // #aabbcc is seven bytes long @@ -82,36 +82,36 @@ pub(super) fn color_hash(color: Color, state: &mut H) { color.hash(state); } +/// Serialize [`iced::Color`] as a hex string. +#[inline] +pub(super) fn serialize_color(color: &Color, serializer: S) -> Result +where + S: Serializer, +{ + // iced::Color to [u8; 4] + let color = color.into_rgba8(); + + // [u8; 4] to hex string, precluding the alpha if it's 0xff. + let hex_color = if color[3] == 255 { + format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]) + } else { + format!( + "#{:02x}{:02x}{:02x}{:02x}", + color[0], color[1], color[2], color[3] + ) + }; + + // Serialize the hex string + serializer.serialize_str(&hex_color) +} + #[cfg(test)] mod tests { use iced::Color; - use serde::{Deserialize, Serialize, Serializer}; + use serde::{Deserialize, Serialize}; use serde_test::{assert_de_tokens_error, assert_tokens, Token}; - use super::deserialize_color; - - /// Serialize [`iced::Color`] as a hex string. - #[inline] - fn serialize_color(color: &Color, serializer: S) -> Result - where - S: Serializer, - { - // iced::Color to [u8; 4] - let color = color.into_rgba8(); - - // [u8; 4] to hex string, precluding the alpha if it's 0xff. - let hex_color = if color[3] != 255 { - format!( - "#{:02x}{:02x}{:02x}{:02x}", - color[0], color[1], color[2], color[3] - ) - } else { - format!("#{:02x}{:02x}{:02x}", color[0], color[1], color[2]) - }; - - // Serialize the hex string - serializer.serialize_str(&hex_color) - } + use super::{deserialize_color, serialize_color}; // https://github.com/catppuccin/catppuccin const CATPPUCCIN_PINK_HEX: &str = "#f5c2e7"; diff --git a/src/gui/styles/types/custom_palette.rs b/src/gui/styles/types/custom_palette.rs index e8c54e8a..f3ea4fb5 100644 --- a/src/gui/styles/types/custom_palette.rs +++ b/src/gui/styles/types/custom_palette.rs @@ -10,7 +10,7 @@ use serde::{de::Error as DeErrorTrait, Deserialize, Serialize}; use crate::gui::styles::custom_themes::{dracula, gruvbox, nord, solarized}; use crate::gui::styles::types::palette::Palette; -use super::color_remote::{color_hash, deserialize_color}; +use super::color_remote::{color_hash, deserialize_color, serialize_color}; const FLOAT_PRECISION: f32 = 10000.0; @@ -19,7 +19,7 @@ const FLOAT_PRECISION: f32 = 10000.0; // defined in the TOML as a single entity rather than two separate tables. This is intentional because // the separation between palette and its extension is an implementation detail that shouldn't be exposed // to custom theme designers. -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] pub struct CustomPalette { /// Base colors for the theme #[serde(flatten)] @@ -30,10 +30,13 @@ pub struct CustomPalette { } /// Extension color for themes. -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] pub struct PaletteExtension { /// Color of favorites star - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub starred: Color, /// Badge/logo alpha pub chart_badge_alpha: f32, @@ -125,7 +128,6 @@ pub enum ExtraStyles { NordLight, SolarizedDark, SolarizedLight, - #[serde(skip)] CustomToml(CustomPalette), } @@ -223,10 +225,10 @@ mod tests { text_body: color!(205, 214, 244), }, extension: PaletteExtension { - starred: color!(249, 226, 175), - round_borders_alpha: 0.1, + starred: color!(249, 226, 175, 0.6666667), + round_borders_alpha: 0.3, round_containers_alpha: 0.15, - chart_badge_alpha: 0.75, + chart_badge_alpha: 0.2, nightly: true, }, } diff --git a/src/gui/styles/types/palette.rs b/src/gui/styles/types/palette.rs index 77b41746..f78ba677 100644 --- a/src/gui/styles/types/palette.rs +++ b/src/gui/styles/types/palette.rs @@ -2,14 +2,14 @@ use iced::Color; use plotters::style::RGBColor; -use serde::Deserialize; +use serde::{Deserialize, Serialize}; use crate::gui::styles::style_constants::{ DAY_STYLE, DEEP_SEA_STYLE, MON_AMOUR_STYLE, NIGHT_STYLE, }; use crate::StyleType; -use super::color_remote::deserialize_color; +use super::color_remote::{deserialize_color, serialize_color}; /// Set of colors to apply to GUI /// @@ -19,25 +19,43 @@ use super::color_remote::deserialize_color; /// - `secondary` and `outgoing` should be complementary colors if possible /// - `text_headers` should be black or white and must have a strong contrast with `secondary` /// - `text_body` should be black or white and must have a strong contrast with `primary` -#[derive(Debug, Clone, Copy, PartialEq, Deserialize)] +#[derive(Debug, Clone, Copy, PartialEq, Deserialize, Serialize)] pub struct Palette { /// Main color of the GUI (background, hovered buttons, active tab) - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub primary: Color, /// Secondary color of the GUI (incoming connections, header, footer, buttons' borders, radio selection) - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub secondary: Color, /// Color of outgoing connections - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub outgoing: Color, /// Color of active buttons (when not hovered) and inactive tabs - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub buttons: Color, /// Color of header and footer text - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub text_headers: Color, /// Color of body and buttons text - #[serde(deserialize_with = "deserialize_color")] + #[serde( + deserialize_with = "deserialize_color", + serialize_with = "serialize_color" + )] pub text_body: Color, } diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index 1f2250e3..5711a221 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -175,25 +175,14 @@ impl Sniffer { Message::Start => self.start(), Message::Reset => return self.reset(), Message::Style(style) => { - // Reset the path for custom styles so that the newly chosen theme loads when sniffnet starts - // Without this, the custom style will always be set on launch regardless of a set theme - self.advanced_settings.style_path = None; self.style = style; self.traffic_chart.change_style(self.style); } Message::LoadStyle(path) => { - self.advanced_settings.style_path = if path.is_empty() { - None - } else { - Some(path.into()) - }; - - if let Some(path) = self.advanced_settings.style_path.as_deref() { - if let Ok(palette) = CustomPalette::from_file(path) { - let style = StyleType::Custom(ExtraStyles::CustomToml(palette)); - self.style = style; - self.traffic_chart.change_style(self.style); - } + self.advanced_settings.style_path = path.clone().into(); + if let Ok(palette) = CustomPalette::from_file(path) { + self.style = StyleType::Custom(ExtraStyles::CustomToml(palette)); + self.traffic_chart.change_style(self.style); } } Message::Waiting => self.update_waiting_dots(), diff --git a/src/translations/translations_3.rs b/src/translations/translations_3.rs index 870444a6..99e753fc 100644 --- a/src/translations/translations_3.rs +++ b/src/translations/translations_3.rs @@ -66,3 +66,11 @@ pub fn file_path_translation(language: Language) -> &'static str { _ => "File path", } } + +pub fn custom_style_translation(language: Language) -> &'static str { + match language { + Language::EN => "Custom style", + Language::IT => "Stile personalizzato", + _ => "Custom style", + } +}