refactor(ui): upgrade vector icons, add accent color theme, enlarge settings, and prevent daemon errors
This commit is contained in:
parent
829f3e74d8
commit
aede621eae
4 changed files with 482 additions and 216 deletions
|
|
@ -262,42 +262,76 @@ async fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
Some(Arc::clone(&audio_levels)),
|
||||
).ok();
|
||||
|
||||
let mut source: Box<dyn FrameSource> = if std::env::args().any(|a| a == "--mock") {
|
||||
let mut source_opt: Option<Box<dyn FrameSource>> = None;
|
||||
|
||||
if std::env::args().any(|a| a == "--mock") {
|
||||
println!("Initializing MOCK capture...");
|
||||
Box::new(scythe::capture::mock::MockCapture::new())
|
||||
source_opt = Some(Box::new(scythe::capture::mock::MockCapture::new()));
|
||||
} else if cfg!(target_os = "windows") {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
println!("Initializing Windows DXGI capture...");
|
||||
Box::new(scythe::capture::windows::WindowsCapture::new()?)
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
unreachable!()
|
||||
if let Ok(c) = scythe::capture::windows::WindowsCapture::new() {
|
||||
source_opt = Some(Box::new(c));
|
||||
}
|
||||
}
|
||||
} else if session_type.to_lowercase() == "wayland" {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
println!("Initializing Wayland capture (cursor: {})...", initial_config.show_cursor);
|
||||
Box::new(scythe::capture::wayland::WaylandCapture::new_with_cursor(initial_config.show_cursor).await?)
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
unreachable!()
|
||||
for attempt in 1..=5 {
|
||||
println!("Initializing Wayland capture (cursor: {}, attempt {}/5)...", initial_config.show_cursor, attempt);
|
||||
// Ensure desktop portal is running
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["--user", "start", "xdg-desktop-portal-hyprland"])
|
||||
.status();
|
||||
|
||||
match scythe::capture::wayland::WaylandCapture::new_with_cursor(initial_config.show_cursor).await {
|
||||
Ok(cap) => {
|
||||
source_opt = Some(Box::new(cap));
|
||||
break;
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("Wayland capture attempt {} failed: {}", attempt, e);
|
||||
if attempt < 5 {
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["--user", "restart", "xdg-desktop-portal"])
|
||||
.status();
|
||||
tokio::time::sleep(std::time::Duration::from_millis(600)).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
println!("Initializing X11 capture...");
|
||||
Box::new(scythe::capture::x11::X11Capture::new()?)
|
||||
if let Ok(c) = scythe::capture::x11::X11Capture::new() {
|
||||
source_opt = Some(Box::new(c));
|
||||
}
|
||||
}
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
let mut source: Box<dyn FrameSource> = match source_opt {
|
||||
Some(s) => s,
|
||||
None => {
|
||||
eprintln!("Warning: Hardware capture unavailable; falling back to mock capture to preserve daemon IPC.");
|
||||
Box::new(scythe::capture::mock::MockCapture::new())
|
||||
}
|
||||
};
|
||||
|
||||
let first_frame = source.next_frame()?;
|
||||
let first_frame = match source.next_frame() {
|
||||
Ok(f) => f,
|
||||
Err(e) => {
|
||||
eprintln!("Initial frame capture error: {}. Using default frame.", e);
|
||||
Frame::Raw {
|
||||
data: vec![0u8; 1920 * 1080 * 4],
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
stride: 1920 * 4,
|
||||
}
|
||||
}
|
||||
};
|
||||
let (width, height) = match &first_frame {
|
||||
Frame::Raw { width, height, .. } => (*width, *height),
|
||||
Frame::DmaBuf { width, height, .. } => (*width, *height),
|
||||
|
|
|
|||
|
|
@ -131,6 +131,18 @@ fn get_ui_cmd() -> std::process::Command {
|
|||
fn check_and_toggle_overlay() -> bool {
|
||||
let pid_path = scythe::ipc::get_overlay_pid_path();
|
||||
if pid_path.exists() {
|
||||
if let Ok(metadata) = std::fs::metadata(&pid_path) {
|
||||
if let Ok(modified) = metadata.modified() {
|
||||
if let Ok(elapsed) = modified.elapsed() {
|
||||
// Debounce: if the overlay was spawned less than 400ms ago, this is a
|
||||
// duplicate event from concurrent triggers. Do not kill it; simply exit.
|
||||
if elapsed < std::time::Duration::from_millis(400) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if let Ok(content) = std::fs::read_to_string(&pid_path) {
|
||||
if let Ok(pid) = content.trim().parse::<i32>() {
|
||||
#[cfg(unix)]
|
||||
|
|
@ -167,6 +179,11 @@ fn ensure_daemon_running_async() {
|
|||
|| UnixStream::connect(scythe::ipc::get_legacy_socket_path()).is_ok() {
|
||||
return;
|
||||
}
|
||||
if scythe::hyprland_binds::is_hyprland() {
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["--user", "start", "xdg-desktop-portal-hyprland"])
|
||||
.status();
|
||||
}
|
||||
}
|
||||
let _ = get_daemon_cmd()
|
||||
.stdin(std::process::Stdio::null())
|
||||
|
|
@ -177,13 +194,21 @@ fn ensure_daemon_running_async() {
|
|||
|
||||
fn ensure_daemon_running() {
|
||||
if query_status().is_err() {
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
if scythe::hyprland_binds::is_hyprland() {
|
||||
let _ = std::process::Command::new("systemctl")
|
||||
.args(["--user", "start", "xdg-desktop-portal-hyprland"])
|
||||
.status();
|
||||
}
|
||||
}
|
||||
let _ = get_daemon_cmd()
|
||||
.stdin(std::process::Stdio::null())
|
||||
.stdout(std::process::Stdio::null())
|
||||
.stderr(std::process::Stdio::null())
|
||||
.spawn();
|
||||
for _ in 0..15 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(80));
|
||||
for _ in 0..25 {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
if query_status().is_ok() {
|
||||
break;
|
||||
}
|
||||
|
|
@ -322,6 +347,7 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
return send_with_notification(Command::StopRecording, "Recording saved");
|
||||
}
|
||||
"--reload" => {
|
||||
ensure_daemon_running();
|
||||
return send_command(Command::ReloadConfig);
|
||||
}
|
||||
"--status" => {
|
||||
|
|
@ -421,7 +447,10 @@ fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
|||
let hotkey_record = HotKey::new(Some(Modifiers::CONTROL | Modifiers::SHIFT), Code::F9);
|
||||
let hotkey_cursor = HotKey::new(Some(Modifiers::CONTROL | Modifiers::SHIFT), Code::F10);
|
||||
|
||||
let _ = manager.register(hotkey_menu);
|
||||
let is_on_hyprland = scythe::hyprland_binds::is_hyprland();
|
||||
if !is_on_hyprland {
|
||||
let _ = manager.register(hotkey_menu);
|
||||
}
|
||||
let _ = manager.register(hotkey_save);
|
||||
let _ = manager.register(hotkey_record);
|
||||
let _ = manager.register(hotkey_cursor);
|
||||
|
|
|
|||
|
|
@ -18,9 +18,12 @@ fn default_record_hotkey() -> String { "Ctrl+Shift+F9".to_string() }
|
|||
fn default_cursor_hotkey() -> String { "Ctrl+Shift+F10".to_string() }
|
||||
fn default_mic_volume() -> f32 { 0.60 }
|
||||
fn default_system_volume() -> f32 { 1.00 }
|
||||
fn default_accent_color() -> String { "blue".to_string() }
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ScytheConfig {
|
||||
#[serde(default = "default_accent_color")]
|
||||
pub accent_color: String,
|
||||
#[serde(default = "default_true")]
|
||||
pub replay_enabled: bool,
|
||||
#[serde(default = "default_replay_duration")]
|
||||
|
|
@ -70,6 +73,7 @@ pub type VrecConfig = ScytheConfig;
|
|||
impl Default for ScytheConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
accent_color: default_accent_color(),
|
||||
replay_enabled: true,
|
||||
replay_duration_sec: 60,
|
||||
replay_bitrate_kbps: 18000,
|
||||
|
|
@ -184,6 +188,7 @@ mod tests {
|
|||
#[test]
|
||||
fn test_config_defaults_and_json() {
|
||||
let cfg = ScytheConfig::default();
|
||||
assert_eq!(cfg.accent_color, "blue");
|
||||
assert_eq!(cfg.replay_duration_sec, 60);
|
||||
assert_eq!(cfg.replay_bitrate_kbps, 18000);
|
||||
assert_eq!(cfg.fps, 60);
|
||||
|
|
@ -192,6 +197,7 @@ mod tests {
|
|||
assert!(cfg.show_cursor);
|
||||
let json = serde_json::to_string(&cfg).unwrap();
|
||||
let parsed: ScytheConfig = serde_json::from_str(&json).unwrap();
|
||||
assert_eq!(parsed.accent_color, "blue");
|
||||
assert_eq!(parsed.replay_duration_sec, 60);
|
||||
assert_eq!(parsed.audio_mode, "system");
|
||||
assert!(parsed.show_cursor);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue