diff options
author | Ricky Kresslein <rk@lakoliu.com> | 2022-05-18 12:51:34 +0300 |
---|---|---|
committer | Ricky Kresslein <rk@lakoliu.com> | 2022-05-18 12:51:34 +0300 |
commit | 1dd125d02f5d66643e39fe2da636d036ed733904 (patch) | |
tree | 230a46a006183346b2fb20d3a7534f7e0cf43c53 | |
parent | 8718d885eb0b0a00655f733395ddc38e13023387 (diff) | |
download | Furtherance-1dd125d02f5d66643e39fe2da636d036ed733904.tar.zst |
Add tasks manually (Issue #42)
-rwxr-xr-x[-rw-r--r--] | .github/FUNDING.yml | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | data/icons/com.lakoliu.Furtherance.Source.svg | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.Devel.svg | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.svg | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | data/icons/hicolor/symbolic/apps/com.lakoliu.Furtherance-symbolic.svg | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | data/screenshots/furtherance-screenshot-edit-task.png | bin | 16533 -> 16533 bytes | |||
-rwxr-xr-x[-rw-r--r--] | data/screenshots/furtherance-screenshot-main.png | bin | 35106 -> 35106 bytes | |||
-rwxr-xr-x[-rw-r--r--] | data/screenshots/furtherance-screenshot-settings.png | bin | 41025 -> 41025 bytes | |||
-rwxr-xr-x[-rw-r--r--] | po/Furtherance.pot | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | po/es.po | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | po/fr_FR.po | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | po/it.po | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | po/nl.po | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | po/pt_BR.po | 0 | ||||
-rwxr-xr-x[-rw-r--r--] | po/sk.po | 0 | ||||
-rwxr-xr-x | src/gtk/window.ui | 6 | ||||
-rwxr-xr-x | src/ui/window.rs | 183 |
17 files changed, 188 insertions, 1 deletions
diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 9f7cabd..9f7cabd 100644..100755 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml diff --git a/data/icons/com.lakoliu.Furtherance.Source.svg b/data/icons/com.lakoliu.Furtherance.Source.svg index 0d7df20..0d7df20 100644..100755 --- a/data/icons/com.lakoliu.Furtherance.Source.svg +++ b/data/icons/com.lakoliu.Furtherance.Source.svg diff --git a/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.Devel.svg b/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.Devel.svg index 105d36b..105d36b 100644..100755 --- a/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.Devel.svg +++ b/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.Devel.svg diff --git a/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.svg b/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.svg index 480fff9..480fff9 100644..100755 --- a/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.svg +++ b/data/icons/hicolor/scalable/apps/com.lakoliu.Furtherance.svg diff --git a/data/icons/hicolor/symbolic/apps/com.lakoliu.Furtherance-symbolic.svg b/data/icons/hicolor/symbolic/apps/com.lakoliu.Furtherance-symbolic.svg index bc16cef..bc16cef 100644..100755 --- a/data/icons/hicolor/symbolic/apps/com.lakoliu.Furtherance-symbolic.svg +++ b/data/icons/hicolor/symbolic/apps/com.lakoliu.Furtherance-symbolic.svg diff --git a/data/screenshots/furtherance-screenshot-edit-task.png b/data/screenshots/furtherance-screenshot-edit-task.png index 4eb0279..4eb0279 100644..100755 --- a/data/screenshots/furtherance-screenshot-edit-task.png +++ b/data/screenshots/furtherance-screenshot-edit-task.png Binary files differdiff --git a/data/screenshots/furtherance-screenshot-main.png b/data/screenshots/furtherance-screenshot-main.png index dc8231b..dc8231b 100644..100755 --- a/data/screenshots/furtherance-screenshot-main.png +++ b/data/screenshots/furtherance-screenshot-main.png Binary files differdiff --git a/data/screenshots/furtherance-screenshot-settings.png b/data/screenshots/furtherance-screenshot-settings.png index 32d8c4c..32d8c4c 100644..100755 --- a/data/screenshots/furtherance-screenshot-settings.png +++ b/data/screenshots/furtherance-screenshot-settings.png Binary files differdiff --git a/po/Furtherance.pot b/po/Furtherance.pot index fbbadf9..fbbadf9 100644..100755 --- a/po/Furtherance.pot +++ b/po/Furtherance.pot diff --git a/po/es.po b/po/es.po index 54927bf..54927bf 100644..100755 --- a/po/es.po +++ b/po/es.po diff --git a/po/fr_FR.po b/po/fr_FR.po index 8e17787..8e17787 100644..100755 --- a/po/fr_FR.po +++ b/po/fr_FR.po diff --git a/po/it.po b/po/it.po index 82df3ed..82df3ed 100644..100755 --- a/po/it.po +++ b/po/it.po diff --git a/po/nl.po b/po/nl.po index 051f41d..051f41d 100644..100755 --- a/po/nl.po +++ b/po/nl.po diff --git a/po/pt_BR.po b/po/pt_BR.po index 107e121..107e121 100644..100755 --- a/po/pt_BR.po +++ b/po/pt_BR.po diff --git a/po/sk.po b/po/sk.po index f6afc6b..f6afc6b 100644..100755 --- a/po/sk.po +++ b/po/sk.po diff --git a/src/gtk/window.ui b/src/gtk/window.ui index 7317b55..aa38ef0 100755 --- a/src/gtk/window.ui +++ b/src/gtk/window.ui @@ -15,6 +15,12 @@ <property name="title">Furtherance</property> </object> </property> + <child> + <object class="GtkButton" id="add_task"> + <property name="tooltip_text" translatable="yes">Add Task</property> + <property name="icon_name">list-add-symbolic</property> + </object> + </child> <child type="end"> <object class="GtkMenuButton" id="app_menu_button"> <property name="tooltip_text" translatable="yes">Main Menu</property> diff --git a/src/ui/window.rs b/src/ui/window.rs index 220491a..fa722b7 100755 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -24,7 +24,7 @@ use std::time::Duration; use std::sync::Mutex; use std::rc::Rc; use std::cell::RefCell; -use chrono::{DateTime, Local, Duration as ChronDur}; +use chrono::{DateTime, Local, NaiveDateTime, ParseError, Duration as ChronDur, offset::TimeZone}; use dbus::blocking::Connection; use itertools::Itertools; @@ -44,6 +44,8 @@ mod imp { #[template_child] pub header_bar: TemplateChild<adw::HeaderBar>, #[template_child] + pub add_task: TemplateChild<gtk::Button>, + #[template_child] pub watch: TemplateChild<gtk::Label>, #[template_child] pub task_input: TemplateChild<gtk::Entry>, @@ -289,6 +291,185 @@ impl FurtheranceWindow { this.save_task(*start_time.borrow(), *stop_time.borrow()); } })); + + imp.add_task.connect_clicked(clone!(@weak self as this => move |_| { + let dialog = gtk::MessageDialog::new( + Some(&this), + gtk::DialogFlags::MODAL, + gtk::MessageType::Question, + gtk::ButtonsType::None, + &format!("<span size='x-large' weight='bold'>{}</span>", &gettext("New Task")), + ); + dialog.set_use_markup(true); + dialog.add_buttons(&[ + (&gettext("Cancel"), gtk::ResponseType::Cancel), + (&gettext("Add"), gtk::ResponseType::Ok) + ]); + + let message_area = dialog.message_area().downcast::<gtk::Box>().unwrap(); + let vert_box = gtk::Box::new(gtk::Orientation::Vertical, 5); + let task_name_edit = gtk::Entry::new(); + task_name_edit.set_placeholder_text(Some(&gettext("Task Name"))); + let task_tags_edit = gtk::Entry::new(); + let tags_placeholder = format!("#{}", &gettext("Tags")); + task_tags_edit.set_placeholder_text(Some(&tags_placeholder)); + + let labels_box = gtk::Box::new(gtk::Orientation::Horizontal, 5); + labels_box.set_homogeneous(true); + let start_label = gtk::Label::new(Some(&gettext("Start"))); + start_label.add_css_class("title-4"); + 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); + + let stop_time = Local::now(); + let start_time = stop_time - ChronDur::seconds(1); + + let mut start_time_w_year = start_time.format("%h %d %Y %H:%M:%S").to_string(); + if !settings_manager::get_bool("show-seconds") { + start_time_w_year = start_time.format("%h %d %Y %H:%M").to_string(); + } + let mut stop_time_w_year = stop_time.format("%h %d %Y %H:%M:%S").to_string(); + if !settings_manager::get_bool("show-seconds") { + stop_time_w_year = stop_time.format("%h %d %Y %H:%M").to_string(); + } + let start_time_edit = gtk::Entry::new(); + start_time_edit.set_text(&start_time_w_year); + let stop_time_edit = gtk::Entry::new(); + stop_time_edit.set_text(&stop_time_w_year); + + let instructions = gtk::Label::new(Some( + &gettext("*Use the format MMM DD YYYY HH:MM:SS"))); + if !settings_manager::get_bool("show-seconds") { + 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( + &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( + &gettext("*Time cannot be in the future."))); + future_error.set_visible(false); + future_error.add_css_class("error_message"); + + let name_error = gtk::Label::new(Some( + &gettext("*Task name cannot be blank."))); + name_error.set_visible(false); + name_error.add_css_class("error_message"); + + vert_box.append(&task_name_edit); + vert_box.append(&task_tags_edit); + labels_box.append(&start_label); + labels_box.append(&stop_label); + times_box.append(&start_time_edit); + times_box.append(&stop_time_edit); + vert_box.append(&labels_box); + vert_box.append(×_box); + vert_box.append(&instructions); + vert_box.append(&time_error); + vert_box.append(&future_error); + vert_box.append(&name_error); + message_area.append(&vert_box); + + dialog.connect_response(clone!(@strong dialog => move |_ , resp| { + if resp == gtk::ResponseType::Ok { + instructions.set_visible(false); + time_error.set_visible(false); + future_error.set_visible(false); + name_error.set_visible(false); + let mut do_not_close = false; + let mut new_start_time_local = Local::now(); + let mut new_stop_time_local = Local::now(); + + // Task Name + if task_name_edit.text().trim().is_empty() { + name_error.set_visible(true); + do_not_close = true; + } + + // Start Time + let new_start_time_str = start_time_edit.text(); + let new_start_time: Result<NaiveDateTime, ParseError>; + if settings_manager::get_bool("show-seconds") { + new_start_time = NaiveDateTime::parse_from_str( + &new_start_time_str, + "%h %d %Y %H:%M:%S"); + } else { + new_start_time = NaiveDateTime::parse_from_str( + &new_start_time_str, + "%h %d %Y %H:%M"); + } + if let Err(_) = new_start_time { + instructions.set_visible(true); + do_not_close = true; + } else { + new_start_time_local = Local.from_local_datetime(&new_start_time.unwrap()).unwrap(); + if (Local::now() - new_start_time_local).num_seconds() < 0 { + future_error.set_visible(true); + do_not_close = true; + } + } + + // Stop Time + let new_stop_time_str = stop_time_edit.text(); + let new_stop_time: Result<NaiveDateTime, ParseError>; + if settings_manager::get_bool("show-seconds") { + new_stop_time = NaiveDateTime::parse_from_str( + &new_stop_time_str, + "%h %d %Y %H:%M:%S"); + } else { + new_stop_time = NaiveDateTime::parse_from_str( + &new_stop_time_str, + "%h %d %Y %H:%M"); + } + if let Err(_) = new_stop_time { + instructions.set_visible(true); + do_not_close = true; + } else { + new_stop_time_local = Local.from_local_datetime(&new_stop_time.unwrap()).unwrap(); + if (Local::now() - new_stop_time_local).num_seconds() < 0 { + future_error.set_visible(true); + do_not_close = true; + } + } + + // Tags + let mut new_tag_list = "".to_string(); + if !task_tags_edit.text().trim().is_empty() { + let new_tags = task_tags_edit.text(); + let mut split_tags: Vec<&str> = new_tags.trim().split("#").collect(); + split_tags = split_tags.iter().map(|x| x.trim()).collect(); + // Don't allow empty tags + split_tags.retain(|&x| !x.trim().is_empty()); + // Handle duplicate tags before they are saved + split_tags = split_tags.into_iter().unique().collect(); + // Lowercase tags + let lower_tags: Vec<String> = split_tags.iter().map(|x| x.to_lowercase()).collect(); + new_tag_list = lower_tags.join(" #"); + } + + if !do_not_close { + let _ = database::db_write(task_name_edit.text().trim(), + new_start_time_local, + new_stop_time_local, + new_tag_list); + this.reset_history_box(); + dialog.close(); + } + + } else if resp == gtk::ResponseType::Cancel { + dialog.close(); + } + }), + ); + + dialog.show(); + })); } fn setup_settings(&self) { |