use iced::widget::text::LineHeight;
use iced::widget::tooltip::Position;
use iced::widget::{Column, Container, PickList, Row, Slider, Space, Text, Tooltip, button};
use iced::{Alignment, Length, Padding};
use crate::gui::components::button::{button_open_file, row_open_link_tooltip};
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::button::ButtonType;
use crate::gui::styles::container::ContainerType;
use crate::gui::styles::rule::RuleType;
use crate::gui::styles::style_constants::{FONT_SIZE_SUBTITLE, TOOLTIP_DELAY};
use crate::gui::styles::text::TextType;
use crate::gui::types::message::Message;
use crate::gui::types::settings::Settings;
use crate::mmdb::types::mmdb_reader::{MmdbReader, MmdbReaders};
use crate::networking::types::ip_blacklist::IpBlacklist;
use crate::translations::translations::language_translation;
use crate::translations::translations_2::country_translation;
use crate::translations::translations_3::{
mmdb_files_translation, params_not_editable_translation, zoom_translation,
};
use crate::translations::translations_4::share_feedback_translation;
use crate::translations::translations_5::ip_blacklist_translation;
use crate::utils::formatted_strings::get_path_termination_string;
use crate::utils::types::file_info::FileInfo;
use crate::utils::types::icon::Icon;
use crate::utils::types::web_page::WebPage;
use crate::{Language, Sniffer, StyleType};
pub fn settings_general_page(sniffer: &Sniffer) -> Container<'_, Message, StyleType> {
let Settings {
language,
color_gradient,
..
} = sniffer.conf.settings;
let content = Column::new()
.align_x(Alignment::Center)
.width(Length::Fill)
.push(settings_header(color_gradient, language))
.push(get_settings_tabs(SettingsPage::General, language))
.push(Space::new().height(10))
.push(column_all_general_setting(sniffer));
Container::new(content)
.height(400)
.width(800)
.class(ContainerType::Modal)
}
fn column_all_general_setting(sniffer: &Sniffer) -> Column<'_, Message, StyleType> {
let Settings {
language,
scale_factor,
ref mmdb_country,
ref mmdb_asn,
ip_blacklist: ref ip_blacklist_str,
..
} = sniffer.conf.settings;
let ip_blacklist = &sniffer.ip_blacklist;
let is_editable = sniffer.running_page.is_none();
let mut column = Column::new()
.align_x(Alignment::Center)
.padding([5, 10])
.push(row_language_scale_factor(language, scale_factor))
.push(RuleType::Standard.horizontal(25))
.push(Space::new().height(10));
if !is_editable {
column = column
.push(
Container::new(Text::new(params_not_editable_translation(language)))
.padding(10.0)
.class(ContainerType::Badge),
)
.push(Space::new().height(10));
}
let import_files_row = Row::new()
.align_y(Alignment::Start)
.height(100)
.push(mmdb_settings(
is_editable,
language,
mmdb_country,
mmdb_asn,
&sniffer.mmdb_readers,
))
.push(RuleType::Standard.vertical(25))
.push(blacklist_selection(
is_editable,
ip_blacklist_str,
ip_blacklist,
language,
));
column = column.push(import_files_row);
column
}
fn row_language_scale_factor<'a>(
language: Language,
scale_factor: f32,
) -> Row<'a, Message, StyleType> {
Row::new()
.align_y(Alignment::Start)
.height(100)
.push(language_picklist(language))
.push(RuleType::Standard.vertical(25))
.push(scale_factor_slider(language, scale_factor))
.push(RuleType::Standard.vertical(25))
.push(need_help(language))
}
fn language_picklist<'a>(language: Language) -> Container<'a, Message, StyleType> {
let mut flag_row = Row::new()
.align_y(Alignment::Center)
.spacing(10)
.push(language.get_flag());
if !language.is_up_to_date() {
flag_row = flag_row.push(
Tooltip::new(
button(
Text::new("!")
.class(TextType::Danger)
.align_y(Alignment::Center)
.align_x(Alignment::Center)
.size(15)
.line_height(LineHeight::Relative(1.0)),
)
.on_press(Message::OpenWebPage(WebPage::IssueLanguages))
.padding(2)
.height(20)
.width(20)
.class(ButtonType::Alert),
row_open_link_tooltip("The selected language is not\nfully updated to version 1.5"),
Position::FollowCursor,
)
.class(ContainerType::Tooltip)
.delay(TOOLTIP_DELAY),
);
}
let content = Column::new()
.align_x(Alignment::Center)
.push(
Text::new(language_translation(language))
.class(TextType::Subtitle)
.size(FONT_SIZE_SUBTITLE),
)
.push(Space::new().height(Length::Fill))
.push(flag_row)
.push(Space::new().height(10))
.push(
PickList::new(
&Language::ALL[..],
Some(language),
Message::LanguageSelection,
)
.menu_height(200)
.padding([2, 7]),
)
.push(Space::new().height(Length::Fill));
Container::new(content)
.width(Length::Fill)
.align_x(Alignment::Center)
.align_y(Alignment::Center)
}
fn scale_factor_slider<'a>(
language: Language,
scale_factor: f32,
) -> Container<'a, Message, StyleType> {
let slider_width = 130.0 / scale_factor;
let slider_val = scale_factor.log(3.0);
Container::new(
Column::new()
.align_x(Alignment::Center)
.push(
Text::new(zoom_translation(language))
.class(TextType::Subtitle)
.size(FONT_SIZE_SUBTITLE),
)
.push(Space::new().height(Length::Fill))
.push(Text::new(format!("{:.0}%", scale_factor * 100.0)))
.push(Space::new().height(5))
.push(
Slider::new(-1.0..=1.0, slider_val, |slider_val| {
let scale_factor_str = format!("{:.1}", 3.0_f32.powf(slider_val));
let scale_factor = scale_factor_str.parse().unwrap_or(1.0);
Message::ChangeScaleFactor(scale_factor)
})
.step(0.01)
.width(slider_width),
)
.push(Space::new().height(Length::Fill)),
)
.width(Length::Fill)
.align_x(Alignment::Center)
.align_y(Alignment::Center)
}
fn need_help<'a>(language: Language) -> Container<'a, Message, StyleType> {
let content = Column::new()
.align_x(Alignment::Center)
.push(
Text::new(share_feedback_translation(language))
.class(TextType::Subtitle)
.size(FONT_SIZE_SUBTITLE),
)
.push(Space::new().height(Length::Fill))
.push(
Tooltip::new(
button(
Icon::Feedback
.to_text()
.align_y(Alignment::Center)
.align_x(Alignment::Center)
.size(20)
.line_height(LineHeight::Relative(1.0)),
)
.on_press(Message::OpenWebPage(WebPage::Issues))
.padding(Padding::new(2.0).top(5))
.height(40)
.width(60),
row_open_link_tooltip("GitHub Issues"),
Position::Right,
)
.gap(5)
.class(ContainerType::Tooltip)
.delay(TOOLTIP_DELAY),
)
.push(Space::new().height(Length::Fill));
Container::new(content)
.width(Length::Fill)
.align_x(Alignment::Center)
.align_y(Alignment::Center)
}
fn mmdb_settings<'a>(
is_editable: bool,
language: Language,
country_path: &str,
asn_path: &str,
mmdb_readers: &MmdbReaders,
) -> Column<'a, Message, StyleType> {
Column::new()
.width(Length::Fill)
.spacing(5)
.align_x(Alignment::Center)
.push(
Text::new(mmdb_files_translation(language))
.class(TextType::Subtitle)
.size(FONT_SIZE_SUBTITLE),
)
.push(mmdb_selection_row(
is_editable,
Message::CustomCountryDb,
country_path,
&mmdb_readers.country,
country_translation(language),
language,
))
.push(mmdb_selection_row(
is_editable,
Message::CustomAsnDb,
asn_path,
&mmdb_readers.asn,
"ASN",
language,
))
}
fn mmdb_selection_row<'a>(
is_editable: bool,
message: fn(String) -> Message,
custom_path: &str,
mmdb_reader: &MmdbReader,
caption: &str,
language: Language,
) -> Row<'a, Message, StyleType> {
let is_error = if custom_path.is_empty() {
false
} else {
match *mmdb_reader {
MmdbReader::Default(_) | MmdbReader::Empty => true,
MmdbReader::Custom(_) => false,
}
};
Row::new()
.align_y(Alignment::Center)
.push(Text::new(format!("{caption}: ")))
.push(
Text::new(get_path_termination_string(custom_path, 25)).class(if is_error {
TextType::Danger
} else {
TextType::Standard
}),
)
.push(if custom_path.is_empty() {
button_open_file(
custom_path.to_owned(),
FileInfo::Database,
language,
is_editable,
message,
)
} else {
button_clear_mmdb(message, is_editable)
})
}
fn blacklist_selection<'a>(
is_editable: bool,
custom_path: &str,
ip_blacklist: &IpBlacklist,
language: Language,
) -> Column<'a, Message, StyleType> {
let is_error = if custom_path.is_empty() {
false
} else {
ip_blacklist.is_invalid()
};
let message = Message::LoadIpBlacklist;
Column::new()
.width(Length::Fill)
.spacing(5)
.align_x(Alignment::Center)
.push(
Text::new(ip_blacklist_translation(language))
.class(TextType::Subtitle)
.size(FONT_SIZE_SUBTITLE),
)
.push(
Row::new()
.align_y(Alignment::Center)
.push(
Text::new(get_path_termination_string(custom_path, 25)).class(if is_error {
TextType::Danger
} else {
TextType::Standard
}),
)
.push(if custom_path.is_empty() {
button_open_file(
custom_path.to_owned(),
FileInfo::Blacklist,
language,
is_editable,
message,
)
} else {
button_clear_mmdb(message, is_editable)
}),
)
}
fn button_clear_mmdb<'a>(
message: fn(String) -> Message,
is_editable: bool,
) -> Tooltip<'a, Message, StyleType> {
let mut button = button(
Text::new("×")
.align_y(Alignment::Center)
.align_x(Alignment::Center)
.size(15)
.line_height(LineHeight::Relative(1.0)),
)
.padding(2)
.height(20)
.width(20);
if is_editable {
button = button.on_press(message(String::new()));
}
Tooltip::new(button, "", Position::Right).delay(TOOLTIP_DELAY)
}