use crate::theme::Theme;
use crate::widgets::{
Button,
secure_text_edit::{SecureTextEdit, SecureTextEditOutput},
};
use egui::*;
use egui_lucide::Lucide;
#[cfg(all(feature = "qr-scanner", any(target_os = "linux", target_os = "windows")))]
use super::QRScanner;
use secure_types::SecureString;
#[derive(Clone)]
pub struct SecureInputField {
open: bool,
pub(crate) text: SecureString,
text_hidden: bool,
id: &'static str,
icon_size: Vec2,
min_size: Vec2,
inner_margin: Option<Margin>,
#[cfg(all(feature = "qr-scanner", any(target_os = "linux", target_os = "windows")))]
qr_scanner: QRScanner,
qr_enabled: bool,
}
impl SecureInputField {
pub fn new(id: &'static str, text_hidden: bool, open: bool) -> Self {
Self {
open,
text: SecureString::new_with_capacity(32).unwrap(),
text_hidden,
id,
icon_size: vec2(20.0, 20.0),
min_size: vec2(300.0, 20.0),
inner_margin: None,
#[cfg(all(feature = "qr-scanner", any(target_os = "linux", target_os = "windows")))]
qr_scanner: QRScanner::new(),
qr_enabled: true,
}
}
pub fn is_open(&self) -> bool {
self.open
}
pub fn open(&mut self) {
self.open = true;
}
pub fn close(&mut self) {
self.open = false;
}
pub fn erase(&mut self) {
self.text.erase();
}
pub fn icon_size(mut self, size: Vec2) -> Self {
self.icon_size = size;
self
}
pub fn with_min_size(mut self, size: Vec2) -> Self {
self.min_size = size;
self
}
pub fn min_size(&self) -> Vec2 {
self.min_size
}
pub fn inner_margin(mut self, margin: Margin) -> Self {
self.inner_margin = Some(margin);
self
}
pub fn qr_enabled(mut self, enabled: bool) -> Self {
self.qr_enabled = enabled;
self
}
pub fn is_text_hidden(&self) -> bool {
self.text_hidden
}
pub fn text(&self) -> SecureString {
self.text.clone()
}
pub fn set_id(&mut self, id: &'static str) {
self.id = id;
}
pub fn set_text_hidden(&mut self, text_hidden: bool) {
self.text_hidden = text_hidden;
}
pub fn set_text(&mut self, text: SecureString) {
self.text = text;
}
pub fn set_min_size(&mut self, size: Vec2) {
self.min_size = size;
}
pub fn set_icon_size(&mut self, size: Vec2) {
self.icon_size = size;
}
pub fn set_inner_margin(&mut self, margin: Margin) {
self.inner_margin = Some(margin);
}
pub fn enable_qr_scanner(&mut self) {
self.qr_enabled = true;
}
pub fn disable_qr_scanner(&mut self) {
self.qr_enabled = false;
}
pub fn show(&mut self, ui: &mut Ui) -> Option<SecureTextEditOutput> {
if !self.open {
return None;
}
let ui_size = self.min_size;
let theme = Theme::current(ui.ctx());
let mut hidden = self.is_text_hidden();
let field_name = self.id.to_string();
let img_size = self.icon_size;
ui.label(RichText::new(field_name).size(theme.typography.large));
let response = self.text.secure_mut(|text_str| {
let margin = self.inner_margin.unwrap_or_else(|| Margin::same(theme.inner_margin));
let row_height = (theme.typography.normal + margin.sum().y).max(ui_size.y);
let row_size = vec2(ui_size.x, row_height);
let text_edit = SecureTextEdit::singleline(text_str)
.min_size(ui_size)
.margin(margin)
.password(hidden)
.font(FontId::proportional(theme.typography.normal));
let response = ui.allocate_ui_with_layout(
row_size,
Layout::left_to_right(Align::Center),
|ui| {
let output = text_edit.show(ui);
let text_color = theme.colors.text;
let icon = if hidden { Lucide::EyeOff } else { Lucide::Eye };
let img = icon.size(img_size.x).color(text_color).image();
if ui.add(Button::image(img)).clicked() {
hidden = !hidden;
}
#[cfg(all(feature = "qr-scanner", any(target_os = "linux", target_os = "windows")))]
{
if self.qr_enabled {
let icon = Lucide::ScanQrCode;
let img = icon.size(img_size.x).color(text_color).image();
if ui.add(Button::image(img)).clicked() {
self.qr_scanner.open(ui.ctx().clone());
}
}
}
output
},
);
response
});
#[cfg(all(feature = "qr-scanner", any(target_os = "linux", target_os = "windows")))]
{
if self.qr_enabled {
self.qr_scanner.show(ui.ctx());
if let Some(res) = self.qr_scanner.take_result() {
self.qr_scanner.reset();
self.set_text(res);
}
}
}
self.set_text_hidden(hidden);
Some(response.inner)
}
}