mirror of
https://github.com/xlmnxp/blue-recorder.git
synced 2024-11-23 09:03:10 +03:00
Compare commits
2 Commits
8e039c3df5
...
c601747c79
Author | SHA1 | Date | |
---|---|---|---|
|
c601747c79 | ||
|
965b303832 |
@ -7,6 +7,56 @@
|
|||||||
<property name="logo-icon-name">blue-recorder</property>
|
<property name="logo-icon-name">blue-recorder</property>
|
||||||
<property name="modal">True</property>
|
<property name="modal">True</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkMessageDialog" id="error_dialog">
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="destroy-with-parent">True</property>
|
||||||
|
<property name="modal">True</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkBox">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="orientation">vertical</property>
|
||||||
|
<child type="top">
|
||||||
|
<object class="GtkImage" id="error_image">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="pixel-size">32</property>
|
||||||
|
<property name="icon-name">dialog-error-symbolic</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="center">
|
||||||
|
<object class="GtkLabel" id="error_text">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="label" translatable="yes">label</property>
|
||||||
|
<property name="margin-start">10</property>
|
||||||
|
<property name="margin-end">10</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="start">
|
||||||
|
<object class="GtkExpander" id="error_expander">
|
||||||
|
<property name="label-widget">expander_label</property>
|
||||||
|
<child>
|
||||||
|
<object class="GtkTextView" id="error_details">
|
||||||
|
<property name="receives-default">False</property>
|
||||||
|
<property name="can-focus">False</property>
|
||||||
|
<property name="editable">False</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
<child type="bottom">
|
||||||
|
<object class="GtkButton" id="error_button">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="receives-default">True</property>
|
||||||
|
<property name="label" translatable="yes">label</property>
|
||||||
|
<property name="hexpand">True</property>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
|
</child>
|
||||||
|
</object>
|
||||||
<object class="GtkAdjustment" id="adjustment_delay">
|
<object class="GtkAdjustment" id="adjustment_delay">
|
||||||
<property name="upper">10</property>
|
<property name="upper">10</property>
|
||||||
<property name="step-increment">1</property>
|
<property name="step-increment">1</property>
|
||||||
@ -30,6 +80,11 @@
|
|||||||
<property name="step-increment">1</property>
|
<property name="step-increment">1</property>
|
||||||
<property name="page-increment">10</property>
|
<property name="page-increment">10</property>
|
||||||
</object>
|
</object>
|
||||||
|
<object class="GtkLabel" id="expander_label">
|
||||||
|
<property name="visible">True</property>
|
||||||
|
<property name="can-focus">True</property>
|
||||||
|
<property name="label" translatable="yes">label</property>
|
||||||
|
</object>
|
||||||
<object class="GtkWindow" id="area_chooser_window">
|
<object class="GtkWindow" id="area_chooser_window">
|
||||||
<property name="name">area_chooser_window</property>
|
<property name="name">area_chooser_window</property>
|
||||||
<property name="can-focus">True</property>
|
<property name="can-focus">True</property>
|
||||||
|
@ -63,6 +63,9 @@ blue-recorder = Blue Recorder
|
|||||||
# Copy right
|
# Copy right
|
||||||
copy-right = © 2021 Salem Yaslem
|
copy-right = © 2021 Salem Yaslem
|
||||||
|
|
||||||
|
# Close error dialog
|
||||||
|
close-error-dialog = Close
|
||||||
|
|
||||||
# Run command label
|
# Run command label
|
||||||
default-command = Default command:
|
default-command = Default command:
|
||||||
|
|
||||||
@ -78,15 +81,18 @@ delay-title = Start Recording in…
|
|||||||
# Stop delay timer
|
# Stop delay timer
|
||||||
delay-window-stop = Stop
|
delay-window-stop = Stop
|
||||||
|
|
||||||
# About message
|
|
||||||
dialog-comment = A simple screen recorder for Linux desktop. Supports Wayland & Xorg.
|
|
||||||
|
|
||||||
# Details button
|
# Details button
|
||||||
details-button = Details
|
details-button = Details
|
||||||
|
|
||||||
|
# About message
|
||||||
|
dialog-comment = A simple screen recorder for Linux desktop. Supports Wayland & Xorg.
|
||||||
|
|
||||||
# Run command input
|
# Run command input
|
||||||
enter-command = Enter your command here..
|
enter-command = Enter your command here..
|
||||||
|
|
||||||
|
# Error dialog
|
||||||
|
error-dialog = Error
|
||||||
|
|
||||||
# Frames label
|
# Frames label
|
||||||
file-name = Default filename:
|
file-name = Default filename:
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ use std::thread::sleep;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use subprocess::Exec;
|
use subprocess::Exec;
|
||||||
use filename::Filename;
|
use filename::Filename;
|
||||||
|
use std::io::{Error, ErrorKind};
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Ffmpeg {
|
pub struct Ffmpeg {
|
||||||
@ -45,7 +46,7 @@ pub struct Ffmpeg {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ffmpeg {
|
impl Ffmpeg {
|
||||||
pub fn start_record(&mut self, x: u16, y: u16, width: u16, height: u16) -> Option<()> {
|
pub fn start_record(&mut self, x: u16, y: u16, width: u16, height: u16) -> Result<(), Error> {
|
||||||
self.saved_filename = Some(
|
self.saved_filename = Some(
|
||||||
self.filename
|
self.filename
|
||||||
.0
|
.0
|
||||||
@ -83,7 +84,7 @@ impl Ffmpeg {
|
|||||||
message_dialog.close();
|
message_dialog.close();
|
||||||
|
|
||||||
if answer != ResponseType::Yes {
|
if answer != ResponseType::Yes {
|
||||||
return None;
|
return Err(Error::new(ErrorKind::Interrupted, "failed to overwrite file"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,8 +248,7 @@ impl Ffmpeg {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)) {
|
)) {
|
||||||
println!("failed to start recording");
|
return Err(Error::new(ErrorKind::Interrupted,"failed to start recording"));
|
||||||
return None;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -265,7 +265,7 @@ impl Ffmpeg {
|
|||||||
self.audio_process = Some(Rc::new(RefCell::new(ffmpeg_command.spawn().unwrap())));
|
self.audio_process = Some(Rc::new(RefCell::new(ffmpeg_command.spawn().unwrap())));
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stop_record(&mut self) {
|
pub fn stop_record(&mut self) {
|
||||||
|
32
src/main.rs
32
src/main.rs
@ -11,13 +11,15 @@ mod utils;
|
|||||||
use ffmpeg_interface::Ffmpeg;
|
use ffmpeg_interface::Ffmpeg;
|
||||||
use gtk::glib;
|
use gtk::glib;
|
||||||
use gtk::prelude::*;
|
use gtk::prelude::*;
|
||||||
|
use gtk::TextBuffer;
|
||||||
use gtk::{
|
use gtk::{
|
||||||
AboutDialog, Application, Builder, Button, CheckButton, ComboBoxText, CssProvider, Entry,
|
AboutDialog, Application, Builder, Button, CheckButton, ComboBoxText, CssProvider, Entry,
|
||||||
FileChooserAction, FileChooserNative, Image, Label, SpinButton,
|
FileChooserAction, FileChooserNative, Image, Label, MessageDialog, SpinButton,
|
||||||
ToggleButton, Window,
|
ToggleButton, TextView, Window,
|
||||||
};
|
};
|
||||||
use utils::{get_bundle, is_wayland};
|
use utils::{get_bundle, is_wayland};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
|
use std::io::ErrorKind;
|
||||||
use std::ops::Add;
|
use std::ops::Add;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -69,6 +71,11 @@ pub fn build_ui(application: &Application) {
|
|||||||
let delay_window_button: ToggleButton = builder.object("delay_window_stopbutton").unwrap();
|
let delay_window_button: ToggleButton = builder.object("delay_window_stopbutton").unwrap();
|
||||||
let delay_window_label: Label = builder.object("delay_window_label").unwrap();
|
let delay_window_label: Label = builder.object("delay_window_label").unwrap();
|
||||||
let delay_window_title: Label = builder.object("delay_window_title").unwrap();
|
let delay_window_title: Label = builder.object("delay_window_title").unwrap();
|
||||||
|
let error_dialog: MessageDialog = builder.object("error_dialog").unwrap();
|
||||||
|
let error_dialog_button: Button = builder.object("error_button").unwrap();
|
||||||
|
let error_dialog_label: Label = builder.object("error_text").unwrap();
|
||||||
|
let error_expander_label: Label = builder.object("expander_label").unwrap();
|
||||||
|
let error_message: TextView = builder.object("error_details").unwrap();
|
||||||
let filename_entry: Entry = builder.object("filename").unwrap();
|
let filename_entry: Entry = builder.object("filename").unwrap();
|
||||||
let folder_chooser_button: Button = builder.object("folder_chooser").unwrap();
|
let folder_chooser_button: Button = builder.object("folder_chooser").unwrap();
|
||||||
let folder_chooser_image: Image = builder.object("folder_chooser_image").unwrap();
|
let folder_chooser_image: Image = builder.object("folder_chooser_image").unwrap();
|
||||||
@ -592,14 +599,22 @@ pub fn build_ui(application: &Application) {
|
|||||||
);
|
);
|
||||||
} else if _delay_spin.value() as u64 == 0 {
|
} else if _delay_spin.value() as u64 == 0 {
|
||||||
let _area_capture = area_capture.borrow_mut();
|
let _area_capture = area_capture.borrow_mut();
|
||||||
match _ffmpeg_record_interface.borrow_mut().start_record(
|
let start_record = _ffmpeg_record_interface.borrow_mut().start_record(
|
||||||
_area_capture.x,
|
_area_capture.x,
|
||||||
_area_capture.y,
|
_area_capture.y,
|
||||||
_area_capture.width,
|
_area_capture.width,
|
||||||
_area_capture.height,
|
_area_capture.height,
|
||||||
) {
|
);
|
||||||
None => {
|
match start_record {
|
||||||
// Do nothing if the start_record function return nothing
|
Err(ref error) => {
|
||||||
|
if error.kind() == ErrorKind::Interrupted {
|
||||||
|
// Do nothing if the start_record function interrupted
|
||||||
|
} else {
|
||||||
|
error_dialog_label.set_label(&get_bundle("start-error", None));
|
||||||
|
let text_buffer = TextBuffer::new(None);
|
||||||
|
text_buffer.set_text(&error.to_string());
|
||||||
|
error_message.set_buffer(Some(&text_buffer));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
start_timer(record_time_label.clone());
|
start_timer(record_time_label.clone());
|
||||||
@ -640,6 +655,11 @@ pub fn build_ui(application: &Application) {
|
|||||||
_ffmpeg_record_interface.borrow_mut().clone().play_record();
|
_ffmpeg_record_interface.borrow_mut().clone().play_record();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Error Dialog
|
||||||
|
error_dialog.set_title(Some(&get_bundle("error-dialog", None)));
|
||||||
|
error_dialog_button.set_label(&get_bundle("close-error-dialog", None));
|
||||||
|
error_expander_label.set_label(&get_bundle("details-button", None));
|
||||||
|
|
||||||
// About Dialog
|
// About Dialog
|
||||||
let mut about_icon_path = {
|
let mut about_icon_path = {
|
||||||
let mut current_exec_dir = std::env::current_exe().unwrap();
|
let mut current_exec_dir = std::env::current_exe().unwrap();
|
||||||
|
32
src/utils.rs
32
src/utils.rs
@ -1,7 +1,5 @@
|
|||||||
use fluent_bundle::bundle::FluentBundle;
|
use fluent_bundle::bundle::FluentBundle;
|
||||||
use fluent_bundle::{FluentArgs, FluentResource};
|
use fluent_bundle::{FluentArgs, FluentResource};
|
||||||
use gtk::prelude::{ButtonExt, GtkWindowExt, WidgetExt};
|
|
||||||
use gtk::{Box, Button, ButtonsType, DialogFlags, MessageDialog, MessageType, Orientation, Window};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
pub fn is_wayland() -> bool {
|
pub fn is_wayland() -> bool {
|
||||||
@ -14,21 +12,6 @@ pub fn is_snap() -> bool {
|
|||||||
!std::env::var("SNAP").unwrap_or_default().is_empty()
|
!std::env::var("SNAP").unwrap_or_default().is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum BlueRecorderError {
|
|
||||||
Start,
|
|
||||||
Stop,
|
|
||||||
Play,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn error_message(error_type: BlueRecorderError) -> String {
|
|
||||||
let error_message = match error_type {
|
|
||||||
BlueRecorderError::Start => get_bundle("start-error", None),
|
|
||||||
BlueRecorderError::Stop => get_bundle("stop-error", None),
|
|
||||||
BlueRecorderError::Play => get_bundle("play-error", None),
|
|
||||||
};
|
|
||||||
error_message
|
|
||||||
}
|
|
||||||
|
|
||||||
// Translate
|
// Translate
|
||||||
pub fn get_bundle(message_id: &str, arg: Option<&FluentArgs>) -> String {
|
pub fn get_bundle(message_id: &str, arg: Option<&FluentArgs>) -> String {
|
||||||
let mut ftl_path = {
|
let mut ftl_path = {
|
||||||
@ -63,18 +46,3 @@ pub fn get_bundle(message_id: &str, arg: Option<&FluentArgs>) -> String {
|
|||||||
bundle.format_pattern(bundle.get_message(message_id)
|
bundle.format_pattern(bundle.get_message(message_id)
|
||||||
.unwrap().value().unwrap(), arg, &mut vec![]).to_string()
|
.unwrap().value().unwrap(), arg, &mut vec![]).to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show_error_dialog(message: String, window: Window) {
|
|
||||||
let error_dialog = MessageDialog::new(
|
|
||||||
Some(&window),
|
|
||||||
DialogFlags::all(),
|
|
||||||
MessageType::Error,
|
|
||||||
ButtonsType::Close,
|
|
||||||
&message,
|
|
||||||
);
|
|
||||||
let dialog_box = Box::new(Orientation::Horizontal, 10);
|
|
||||||
let details_button = Button::new();
|
|
||||||
details_button.set_label(&get_bundle("details-button", None));
|
|
||||||
error_dialog.set_child(Some(&details_button));
|
|
||||||
error_dialog.show();
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user