diff options
Diffstat (limited to 'src')
-rwxr-xr-x | src/application.rs | 15 | ||||
-rwxr-xr-x | src/gtk/history_box.ui | 23 | ||||
-rwxr-xr-x | src/gtk/task_details.ui | 6 | ||||
-rwxr-xr-x | src/gtk/window.ui | 2 | ||||
-rwxr-xr-x | src/ui/task_details.rs | 27 | ||||
-rwxr-xr-x | src/ui/task_row.rs | 3 | ||||
-rwxr-xr-x | src/ui/tasks_page.rs | 5 | ||||
-rwxr-xr-x | src/ui/window.rs | 57 |
8 files changed, 83 insertions, 55 deletions
diff --git a/src/application.rs b/src/application.rs index bc90642..e5153da 100755 --- a/src/application.rs +++ b/src/application.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <https://www.gnu.org/licenses/>. +use gettextrs::*; use glib::clone; use gtk::prelude::*; use gtk::subclass::prelude::*; @@ -124,7 +125,7 @@ impl FurtheranceApplication { .program_name("Furtherance") .logo_icon_name(config::APP_ID) .version(config::VERSION) - .comments("Track your time without being tracked.") + .comments(&gettext("Track your time without being tracked.")) .copyright("© 2022 Ricky Kresslein") .authors(vec!["Ricky Kresslein <rk@lakoliu.com>".into()]) .website("https://furtherance.app") @@ -142,17 +143,17 @@ impl FurtheranceApplication { gtk::DialogFlags::MODAL, gtk::MessageType::Question, gtk::ButtonsType::None, - Some("<span size='x-large' weight='bold'>Delete history?</span>"), + Some(&format!("<span size='x-large' weight='bold'>{}</span>", &gettext("Delete history?"))), ); dialog.add_buttons(&[ - ("Cancel", gtk::ResponseType::Reject), - ("Delete", gtk::ResponseType::Accept) + (&gettext("Cancel"), gtk::ResponseType::Reject), + (&gettext("Delete"), gtk::ResponseType::Accept) ]); let message_area = dialog.message_area().downcast::<gtk::Box>().unwrap(); - let explanation = gtk::Label::new(Some("This will delete ALL of your task history.")); + let explanation = gtk::Label::new(Some(&gettext("This will delete ALL of your task history."))); let instructions = gtk::Label::new(Some( - "Type DELETE in the box below then click Delete to proceed.")); + &gettext("Type DELETE in the box below then click Delete to proceed."))); let delete_entry = gtk::Entry::new(); message_area.append(&explanation); message_area.append(&instructions); @@ -160,7 +161,7 @@ impl FurtheranceApplication { dialog.connect_response(clone!(@weak dialog = > move |_, resp| { if resp == gtk::ResponseType::Accept { - if delete_entry.text().to_uppercase() == "DELETE" { + if delete_entry.text().to_uppercase() == gettext("DELETE") { let _ = database::delete_all(); window.reset_history_box(); dialog.close(); diff --git a/src/gtk/history_box.ui b/src/gtk/history_box.ui index b761624..b5c9a34 100755 --- a/src/gtk/history_box.ui +++ b/src/gtk/history_box.ui @@ -31,7 +31,7 @@ <property name="column_spacing">12</property> <child> <object class="GtkImage"> - <property name="icon_name">list-add-symbolic</property> + <property name="icon_name">input-keyboard-symbolic</property> <layout> <property name="column">0</property> <property name="row">0</property> @@ -50,7 +50,7 @@ </child> <child> <object class="GtkImage"> - <property name="icon_name">window-new-symbolic</property> + <property name="icon_name">accessories-text-editor-symbolic</property> <layout> <property name="column">0</property> <property name="row">1</property> @@ -67,6 +67,25 @@ </layout> </object> </child> + <child> + <object class="GtkImage"> + <property name="icon_name">input-mouse-symbolic</property> + <layout> + <property name="column">0</property> + <property name="row">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="halign">start</property> + <property name="label" translatable="yes">Right-click a task to duplicate it</property> + <layout> + <property name="column">1</property> + <property name="row">2</property> + </layout> + </object> + </child> </object> </property> </object> diff --git a/src/gtk/task_details.ui b/src/gtk/task_details.ui index ccbfc1e..003036b 100755 --- a/src/gtk/task_details.ui +++ b/src/gtk/task_details.ui @@ -70,7 +70,7 @@ <property name="spacing">5</property> <child> <object class="GtkLabel"> - <property name="label">Start</property> + <property name="label" translatable="yes">Start</property> <style> <class name="title-2"/> </style> @@ -78,7 +78,7 @@ </child> <child> <object class="GtkLabel"> - <property name="label">Stop</property> + <property name="label" translatable="yes">Stop</property> <style> <class name="title-2"/> </style> @@ -86,7 +86,7 @@ </child> <child> <object class="GtkLabel"> - <property name="label">Total</property> + <property name="label" translatable="yes">Total</property> <style> <class name="title-2"/> </style> diff --git a/src/gtk/window.ui b/src/gtk/window.ui index 186a57a..073dab9 100755 --- a/src/gtk/window.ui +++ b/src/gtk/window.ui @@ -37,6 +37,8 @@ <child> <object class="GtkLabel" id="watch"> <property name="label">00:00:00</property> + <property name="margin_start">12</property> + <property name="margin_end">12</property> <attributes> <attribute name="weight" value="bold"/> <attribute name="scale" value="5"/> diff --git a/src/ui/task_details.rs b/src/ui/task_details.rs index c45d561..7e306e8 100755 --- a/src/ui/task_details.rs +++ b/src/ui/task_details.rs @@ -15,6 +15,7 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use adw::subclass::prelude::*; +use gettextrs::*; use glib::clone; use gtk::subclass::prelude::*; use gtk::{glib, prelude::*, CompositeTemplate}; @@ -163,7 +164,7 @@ impl FurTaskDetails { gtk::DialogFlags::MODAL, gtk::MessageType::Question, gtk::ButtonsType::OkCancel, - "<span size='x-large' weight='bold'>Edit Task</span>", + &format!("<span size='x-large' weight='bold'>{}</span>", &gettext("Edit Task")), ); dialog.set_use_markup(true); @@ -173,9 +174,9 @@ impl FurTaskDetails { task_name_edit.set_text(&task.task_name); let labels_box = gtk::Box::new(gtk::Orientation::Horizontal, 5); labels_box.set_homogeneous(true); - let start_label = gtk::Label::new(Some("Start")); + let start_label = gtk::Label::new(Some(&gettext("Start"))); start_label.add_css_class("title-4"); - let stop_label = gtk::Label::new(Some("Stop")); + let stop_label = gtk::Label::new(Some(&gettext("Stop"))); stop_label.add_css_class("title-4"); let times_box = gtk::Box::new(gtk::Orientation::Horizontal, 5); times_box.set_homogeneous(true); @@ -194,26 +195,26 @@ impl FurTaskDetails { stop_time_edit.set_text(&stop_time_w_year); let instructions = gtk::Label::new(Some( - "*Use the format MMM DD YYYY HH:MM:SS")); + &gettext("*Use the format MMM DD YYYY HH:MM:SS"))); if !settings_manager::get_bool("show-seconds") { - instructions.set_text("*Use the format MMM DD YYYY HH:MM"); + instructions.set_text(&gettext("*Use the format MMM DD YYYY HH:MM")); } instructions.set_visible(false); instructions.add_css_class("error_message"); let time_error = gtk::Label::new(Some( - "*Start time cannot be later than stop time.")); + &gettext("*Start time cannot be later than stop time."))); time_error.set_visible(false); time_error.add_css_class("error_message"); let future_error = gtk::Label::new(Some( - "*Time cannot be in the future.")); + &gettext("*Time cannot be in the future."))); future_error.set_visible(false); future_error.add_css_class("error_message"); let delete_task_btn = gtk::Button::new(); delete_task_btn.set_icon_name("user-trash-symbolic"); - delete_task_btn.set_tooltip_text(Some("Delete task")); + delete_task_btn.set_tooltip_text(Some(&gettext("Delete task"))); delete_task_btn.set_hexpand(false); delete_task_btn.set_vexpand(false); delete_task_btn.set_halign(gtk::Align::End); @@ -239,7 +240,7 @@ impl FurTaskDetails { gtk::DialogFlags::MODAL, gtk::MessageType::Question, gtk::ButtonsType::OkCancel, - Some("<span size='x-large' weight='bold'>Delete task?</span>"), + Some(&format!("<span size='x-large' weight='bold'>{}</span>", &gettext("Delete task?"))), ); delete_confirmation.connect_response(clone!( @@ -462,12 +463,12 @@ impl FurTaskDetails { gtk::DialogFlags::MODAL, gtk::MessageType::Warning, gtk::ButtonsType::None, - Some("<span size='large'>Delete All?</span>"), + Some(&format!("<span size='large'>{}</span>", &gettext("Delete All?"))), ); - dialog.set_secondary_text(Some("This will delete all occurrences of this task on this day.")); + dialog.set_secondary_text(Some(&gettext("This will delete all occurrences of this task on this day."))); dialog.add_buttons(&[ - ("Delete", gtk::ResponseType::Accept), - ("Cancel", gtk::ResponseType::Reject) + (&gettext("Cancel"), gtk::ResponseType::Reject), + (&gettext("Delete"), gtk::ResponseType::Accept) ]); dialog.connect_response(clone!(@strong dialog => move |_,resp|{ diff --git a/src/ui/task_row.rs b/src/ui/task_row.rs index 80d6795..f55aba4 100755 --- a/src/ui/task_row.rs +++ b/src/ui/task_row.rs @@ -109,8 +109,7 @@ impl FurTaskRow { gesture.connect_pressed(clone!(@strong task_name_text => move |gesture, _, _, _| { gesture.set_state(gtk::EventSequenceState::Claimed); let window = FurtheranceWindow::default(); - window.set_task_input_text(task_name_text.to_string()); - window.start_timer(); + window.duplicate_task(task_name_text.to_string()); })); self.add_controller(&gesture); diff --git a/src/ui/tasks_page.rs b/src/ui/tasks_page.rs index 9f0aed3..23439eb 100755 --- a/src/ui/tasks_page.rs +++ b/src/ui/tasks_page.rs @@ -16,6 +16,7 @@ use adw::subclass::prelude::*; use adw::prelude::{PreferencesPageExt, PreferencesGroupExt}; +use gettextrs::*; use gtk::subclass::prelude::*; use gtk::{glib, prelude::*}; use chrono::{DateTime, Local, Duration}; @@ -142,9 +143,9 @@ impl FurTasksPage { for i in 0..uniq_date_list.len() { let group = FurTasksGroup::new(); if uniq_date_list[i] == today { - group.set_title("Today") + group.set_title(&gettext("Today")) } else if uniq_date_list[i] == yesterday{ - group.set_title("Yesterday") + group.set_title(&gettext("Yesterday")) } else { group.set_title(&uniq_date_list[i]) } diff --git a/src/ui/window.rs b/src/ui/window.rs index f49c8b2..c955451 100755 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -15,12 +15,13 @@ // along with this program. If not, see <https://www.gnu.org/licenses/>. use adw::subclass::prelude::AdwApplicationWindowImpl; +use gettextrs::*; use gtk::prelude::*; use gtk::subclass::prelude::*; use gtk::{gio, glib, CompositeTemplate}; use glib::{clone, timeout_add_local}; use std::time::Duration; -use std::sync::{Arc, Mutex}; +use std::sync::Mutex; use std::rc::Rc; use std::cell::RefCell; use chrono::{DateTime, Local, Duration as ChronDur}; @@ -57,6 +58,7 @@ mod imp { pub idle_time_reached: Mutex<bool>, pub subtract_idle: Mutex<bool>, pub idle_start_time: Mutex<String>, + pub running: Mutex<bool>, } #[glib::object_subclass] @@ -101,7 +103,7 @@ impl FurtheranceWindow { .expect("Failed to create FurtheranceWindow") } - pub fn inapp_notification(&self, text: &str) { + pub fn display_toast(&self, text: &str) { // Display in-app notifications let imp = imp::FurtheranceWindow::from_instance(self); let toast = adw::Toast::new(text); @@ -161,22 +163,23 @@ impl FurtheranceWindow { fn setup_signals(&self) { let imp = imp::FurtheranceWindow::from_instance(self); - let running = Arc::new(Mutex::new(false)); + // running = false + *imp.running.lock().unwrap() = false; let start_time = Rc::new(RefCell::new(Local::now())); let stop_time = Rc::new(RefCell::new(Local::now())); imp.start_button.connect_clicked(clone!( - @weak self as this, - @strong running => move |button| { + @weak self as this => move |button| { + let imp2 = imp::FurtheranceWindow::from_instance(&this); if this.get_task_text().trim().is_empty() { let dialog = gtk::MessageDialog::with_markup( Some(&this), gtk::DialogFlags::MODAL, gtk::MessageType::Error, gtk::ButtonsType::Ok, - Some("<span size='large'>No Task Name</span>"), + Some(&format!("<span size='large'>{}</span>", &gettext("No Task Name"))), ); - dialog.set_secondary_text(Some("Enter a task name to start the timer.")); + dialog.set_secondary_text(Some(&gettext("Enter a task name to start the timer."))); dialog.show(); dialog.connect_response(clone!(@strong dialog => move |_,_|{ @@ -184,17 +187,18 @@ impl FurtheranceWindow { })); } else { - if !*running.lock().unwrap() { + if !*imp2.running.lock().unwrap() { let mut secs: u32 = 0; let mut mins: u32 = 0; let mut hrs: u32 = 0; - *running.lock().unwrap() = true; + *imp2.running.lock().unwrap() = true; *start_time.borrow_mut() = Local::now(); this.activate_task_input(false); let duration = Duration::new(1,0); - timeout_add_local(duration, clone!(@strong running as running_clone => move || { - if *running_clone.lock().unwrap() { + timeout_add_local(duration, clone!(@strong this as this_clone => move || { + let imp3 = imp::FurtheranceWindow::from_instance(&this_clone); + if *imp3.running.lock().unwrap() { secs += 1; if secs > 59 { secs = 0; @@ -205,14 +209,14 @@ impl FurtheranceWindow { } } let watch_text: &str = &format!("{:02}:{:02}:{:02}", hrs, mins, secs).to_string(); - this.set_watch_time(watch_text); + this_clone.set_watch_time(watch_text); } - Continue(*running_clone.lock().unwrap()) + Continue(*imp3.running.lock().unwrap()) })); button.set_icon_name("media-playback-stop-symbolic"); } else { *stop_time.borrow_mut() = Local::now(); - *running.lock().unwrap() = false; + *imp2.running.lock().unwrap() = false; button.set_icon_name("media-playback-start-symbolic"); this.set_watch_time("00:00:00"); this.activate_task_input(true); @@ -282,19 +286,20 @@ impl FurtheranceWindow { let m = (idle_time / 60) - (h * 60); let s = idle_time - (m * 60); let idle_time_str = format!( - "You have been idle for {:02}:{:02}:{:02}.\nWould you like to discard that time, or continue the clock?", - h, m, s); + "{}{:02}:{:02}:{:02}{}", gettext("You have been idle for "), h, m, s, + gettext(".\nWould you like to discard that time, or continue the clock?") + ); let dialog = gtk::MessageDialog::with_markup( Some(self), gtk::DialogFlags::MODAL, gtk::MessageType::Warning, gtk::ButtonsType::None, - Some("<span size='x-large' weight='bold'>Edit Task</span>"), + Some(&format!("<span size='x-large' weight='bold'>{}</span>", &gettext("Edit Task"))), ); dialog.add_buttons(&[ - ("Discard", gtk::ResponseType::Reject), - ("Continue", gtk::ResponseType::Accept) + (&gettext("Discard"), gtk::ResponseType::Reject), + (&gettext("Continue"), gtk::ResponseType::Accept) ]); dialog.set_secondary_text(Some(&idle_time_str)); @@ -328,14 +333,14 @@ impl FurtheranceWindow { *imp.subtract_idle.lock().unwrap() = val; } - pub fn set_task_input_text(&self, text: String) { + pub fn duplicate_task(&self, task_name_text: String) { let imp = imp::FurtheranceWindow::from_instance(self); - imp.task_input.set_text(&text); - } - - pub fn start_timer(&self) { - let imp = imp::FurtheranceWindow::from_instance(self); - imp.start_button.emit_clicked(); + if !*imp.running.lock().unwrap() { + imp.task_input.set_text(&task_name_text); + imp.start_button.emit_clicked(); + } else { + self.display_toast("Stop the timer to duplicate a task."); + } } } |