feat: add cli option and ctrl+u clears password
- Add `--hide-password` CLI flag - Show temporary "CLEARED" feedback on password clear
This commit is contained in:
+5
-5
@@ -43,8 +43,8 @@ default = ["networking"]
|
||||
networking = ["dep:reqwest", "tokio/net"]
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z" # Optimize for size
|
||||
lto = true # Enable Link Time Optimization
|
||||
codegen-units = 1 # Reduce parallel code gen to allow better size optimization
|
||||
panic = "abort" # Remove heavy stack unwinding code
|
||||
strip = true # Automatically strip symbols and debug info
|
||||
opt-level = "z"
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
strip = true
|
||||
|
||||
+14
-10
@@ -6,13 +6,13 @@ use std::path::PathBuf;
|
||||
#[derive(Parser, Debug, Clone, Serialize, Deserialize)]
|
||||
#[command(author, version, about, long_about = None)]
|
||||
pub struct Config {
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "false", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue)]
|
||||
pub screenshots: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "false", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue)]
|
||||
pub clock: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub indicator: bool,
|
||||
|
||||
#[arg(long, default_value = "100")]
|
||||
@@ -54,7 +54,7 @@ pub struct Config {
|
||||
#[arg(long, default_value = "E5A445", value_parser = util::parse_hex_color)]
|
||||
pub caps_lock_text_color: (f64, f64, f64, f64),
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub show_caps_lock_text: bool,
|
||||
|
||||
#[arg(long, default_value = "00000000", value_parser = util::parse_hex_color)]
|
||||
@@ -85,22 +85,25 @@ pub struct Config {
|
||||
#[arg(long)]
|
||||
pub log_file: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub show_media: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub show_battery: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub show_network: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub show_bluetooth: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "true", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue, default_value_t = true)]
|
||||
pub show_album_art: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::Set, num_args = 0..=1, default_value = "false", default_missing_value = "true")]
|
||||
#[arg(long, action = clap::ArgAction::SetTrue)]
|
||||
pub hide_password: bool,
|
||||
|
||||
#[arg(long, action = clap::ArgAction::SetTrue)]
|
||||
pub show_keyboard_layout: bool,
|
||||
|
||||
#[arg(long)]
|
||||
@@ -203,6 +206,7 @@ impl Config {
|
||||
merge_bool(&mut config.show_network, "show_network");
|
||||
merge_bool(&mut config.show_bluetooth, "show_bluetooth");
|
||||
merge_bool(&mut config.show_album_art, "show_album_art");
|
||||
merge_bool(&mut config.hide_password, "hide_password");
|
||||
merge_bool(&mut config.show_keyboard_layout, "show_keyboard_layout");
|
||||
|
||||
if !is_cli("image") {
|
||||
|
||||
@@ -30,6 +30,15 @@ impl InputHandler {
|
||||
// Update Caps Lock state
|
||||
self.caps_lock = modifiers.caps_lock;
|
||||
|
||||
if modifiers.ctrl && keysym == Keysym::u {
|
||||
if !self.password_buffer.is_empty() {
|
||||
self.password_buffer.clear();
|
||||
self.cursor_position = 0;
|
||||
return InputAction::PasswordCleared;
|
||||
}
|
||||
return InputAction::None;
|
||||
}
|
||||
|
||||
// Handle special keys first using keysym
|
||||
use smithay_client_toolkit::seat::keyboard::Keysym;
|
||||
match keysym {
|
||||
@@ -37,6 +46,9 @@ impl InputHandler {
|
||||
if !self.password_buffer.is_empty() && self.cursor_position > 0 {
|
||||
self.cursor_position -= 1;
|
||||
self.password_buffer.remove(self.cursor_position);
|
||||
if self.password_buffer.is_empty() {
|
||||
return InputAction::PasswordCleared;
|
||||
}
|
||||
}
|
||||
return InputAction::PasswordChanged;
|
||||
}
|
||||
@@ -113,6 +125,7 @@ impl InputHandler {
|
||||
pub enum InputAction {
|
||||
None,
|
||||
PasswordChanged,
|
||||
PasswordCleared,
|
||||
SubmitPassword(Zeroizing<String>),
|
||||
Cancel,
|
||||
}
|
||||
|
||||
@@ -174,6 +174,9 @@ impl LockedSurface {
|
||||
self.input_handler.set_key_highlight();
|
||||
self.key_highlight_shown = false;
|
||||
}
|
||||
InputAction::PasswordCleared => {
|
||||
self.renderer.show_cleared_feedback();
|
||||
}
|
||||
InputAction::SubmitPassword(_) => {
|
||||
self.input_handler.set_key_highlight();
|
||||
self.key_highlight_shown = false;
|
||||
|
||||
@@ -14,8 +14,10 @@ pub struct Renderer {
|
||||
fade_alpha: f64,
|
||||
wrong_password_shown: bool,
|
||||
key_highlight_shown: bool,
|
||||
cleared_feedback_shown: bool,
|
||||
wrong_password_start: Option<Instant>,
|
||||
key_highlight_start: Option<Instant>,
|
||||
cleared_feedback_start: Option<Instant>,
|
||||
key_highlight_angle: f64,
|
||||
background: Option<ImageSurface>,
|
||||
password_display: String,
|
||||
@@ -51,8 +53,10 @@ impl Renderer {
|
||||
fade_alpha: 0.0,
|
||||
wrong_password_shown: false,
|
||||
key_highlight_shown: false,
|
||||
cleared_feedback_shown: false,
|
||||
wrong_password_start: None,
|
||||
key_highlight_start: None,
|
||||
cleared_feedback_start: None,
|
||||
key_highlight_angle: 0.0,
|
||||
background: None,
|
||||
password_display: String::new(),
|
||||
@@ -183,6 +187,12 @@ impl Renderer {
|
||||
self.key_highlight_angle = ((random_val % 360) as f64).to_radians();
|
||||
}
|
||||
|
||||
/// Show cleared feedback
|
||||
pub fn show_cleared_feedback(&mut self) {
|
||||
self.cleared_feedback_shown = true;
|
||||
self.cleared_feedback_start = Some(Instant::now());
|
||||
}
|
||||
|
||||
/// Set the password display string (masked)
|
||||
pub fn set_password_display(&mut self, password: String) {
|
||||
self.password_display = password;
|
||||
@@ -250,6 +260,10 @@ impl Renderer {
|
||||
self.draw_key_highlight_feedback();
|
||||
}
|
||||
|
||||
if self.cleared_feedback_shown {
|
||||
self.draw_cleared_feedback();
|
||||
}
|
||||
|
||||
self.update_feedback_timers();
|
||||
}
|
||||
|
||||
@@ -376,6 +390,9 @@ impl Renderer {
|
||||
}
|
||||
|
||||
fn draw_password_display(&self) {
|
||||
if self.config.hide_password {
|
||||
return;
|
||||
}
|
||||
let center_x = self.width as f64 / 2.0;
|
||||
let center_y = self.height as f64 / 2.0;
|
||||
let radius = self.config.indicator_radius as f64;
|
||||
@@ -476,6 +493,56 @@ impl Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_cleared_feedback(&self) {
|
||||
let center_x = self.width as f64 / 2.0;
|
||||
let center_y = self.height as f64 / 2.0;
|
||||
let radius = self.config.indicator_radius as f64;
|
||||
let thickness = self.config.indicator_thickness as f64;
|
||||
let intensity = if let Some(start) = self.cleared_feedback_start {
|
||||
let elapsed = start.elapsed();
|
||||
let duration = std::time::Duration::from_millis(500);
|
||||
if elapsed < duration {
|
||||
1.0 - (elapsed.as_secs_f64() / duration.as_secs_f64())
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
} else {
|
||||
0.0
|
||||
};
|
||||
|
||||
if intensity > 0.0 {
|
||||
self.context.new_path();
|
||||
self.context
|
||||
.set_source_rgba(1.0, 0.0, 0.0, intensity * self.fade_alpha * 0.5);
|
||||
self.context.arc(
|
||||
center_x,
|
||||
center_y,
|
||||
radius - thickness / 2.0,
|
||||
0.0,
|
||||
2.0 * std::f64::consts::PI,
|
||||
);
|
||||
self.context.fill().unwrap();
|
||||
|
||||
self.context.new_path();
|
||||
self.context
|
||||
.set_source_rgba(1.0, 0.0, 0.0, intensity * self.fade_alpha);
|
||||
self.context.set_line_width(thickness + 4.0);
|
||||
self.context
|
||||
.arc(center_x, center_y, radius, 0.0, 2.0 * std::f64::consts::PI);
|
||||
self.context.stroke().unwrap();
|
||||
|
||||
self.context.new_path();
|
||||
self.context.set_font_size(24.0);
|
||||
self.context
|
||||
.set_source_rgba(1.0, 1.0, 1.0, intensity * self.fade_alpha);
|
||||
let text = "CLEARED";
|
||||
let te = self.context.text_extents(text).unwrap();
|
||||
self.context
|
||||
.move_to(center_x - te.width() / 2.0, center_y + te.height() / 2.0);
|
||||
self.context.show_text(text).unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn update_feedback_timers(&mut self) {
|
||||
self.update_uptime();
|
||||
if let Some(start) = self.wrong_password_start {
|
||||
@@ -490,6 +557,12 @@ impl Renderer {
|
||||
self.key_highlight_start = None;
|
||||
}
|
||||
}
|
||||
if let Some(start) = self.cleared_feedback_start {
|
||||
if start.elapsed() > std::time::Duration::from_millis(500) {
|
||||
self.cleared_feedback_shown = false;
|
||||
self.cleared_feedback_start = None;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_media(&mut self) {
|
||||
|
||||
Reference in New Issue
Block a user