From 6f5ed43f98032cbeb1dc11f8015658755cef794b Mon Sep 17 00:00:00 2001 From: Daniel Prieto Date: Mon, 29 Jun 2026 10:24:29 +0200 Subject: [PATCH 01/13] full width task list --- src/modules/Tasks/ui/task-list-panel.ui | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/src/modules/Tasks/ui/task-list-panel.ui b/src/modules/Tasks/ui/task-list-panel.ui index 4603ff4..b04740d 100644 --- a/src/modules/Tasks/ui/task-list-panel.ui +++ b/src/modules/Tasks/ui/task-list-panel.ui @@ -91,20 +91,16 @@ - - - - start - none - 18 - 18 - 12 - 12 - - - + + start + none + 18 + 18 + 12 + 12 + From a059a9a666c7a4c9e7075614d85b859543c272ea Mon Sep 17 00:00:00 2001 From: Daniel Prieto Date: Mon, 29 Jun 2026 10:42:45 +0200 Subject: [PATCH 02/13] completed_at field added --- meson.build | 1 + src/database/Database.vala | 1 + .../003_add_completed_at_to_tasks.vala | 18 ++++++++++++++ .../Backup/actions/ImportGroupAction.vala | 2 +- .../Backup/controllers/BackupController.vala | 1 + .../Backup/services/BackupSerializer.vala | 6 +++++ src/modules/Tasks/models/Task.vala | 24 ++++++++++++++++--- 7 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 src/database/migrations/003_add_completed_at_to_tasks.vala diff --git a/meson.build b/meson.build index 82dc74f..f8cb765 100644 --- a/meson.build +++ b/meson.build @@ -32,6 +32,7 @@ queue_sources = files( 'src/database/Database.vala', 'src/database/migrations/001_create_groups_table.vala', 'src/database/migrations/002_create_tasks_table.vala', + 'src/database/migrations/003_add_completed_at_to_tasks.vala', 'src/modules/Groups/models/Group.vala', 'src/modules/Groups/validators/GroupStoreValidator.vala', 'src/modules/Groups/actions/ListGroupsAction.vala', diff --git a/src/database/Database.vala b/src/database/Database.vala index 0e6b454..4ad5235 100644 --- a/src/database/Database.vala +++ b/src/database/Database.vala @@ -33,6 +33,7 @@ namespace Queue { Migration[] migrations = { new CreateGroupsTable(), new CreateTasksTable(), + new AddCompletedAtToTasks(), }; var applied_version = current_version(); diff --git a/src/database/migrations/003_add_completed_at_to_tasks.vala b/src/database/migrations/003_add_completed_at_to_tasks.vala new file mode 100644 index 0000000..af1ca5d --- /dev/null +++ b/src/database/migrations/003_add_completed_at_to_tasks.vala @@ -0,0 +1,18 @@ +namespace Queue { + + public class AddCompletedAtToTasks : Object, Migration + { + + public int version { + get { return 3; } + } + + public string up() + { + return + """ + ALTER TABLE tasks ADD COLUMN completed_at TEXT NOT NULL DEFAULT ''; + """; + } + } +} diff --git a/src/modules/Backup/actions/ImportGroupAction.vala b/src/modules/Backup/actions/ImportGroupAction.vala index 771e1b7..e2b28dd 100644 --- a/src/modules/Backup/actions/ImportGroupAction.vala +++ b/src/modules/Backup/actions/ImportGroupAction.vala @@ -20,7 +20,7 @@ namespace Queue.Backup { var stored = Queue.Tasks.Task.create(database, created.id, task.title, task.description, task.important); if (task.done) { - Queue.Tasks.Task.mark_done(database, stored.id, true); + Queue.Tasks.Task.restore_completion(database, stored.id, true, task.completed_at); } } } diff --git a/src/modules/Backup/controllers/BackupController.vala b/src/modules/Backup/controllers/BackupController.vala index b6150e0..41b58a2 100644 --- a/src/modules/Backup/controllers/BackupController.vala +++ b/src/modules/Backup/controllers/BackupController.vala @@ -99,6 +99,7 @@ namespace Queue.Backup { backup_task.description = task.description; backup_task.done = task.done; backup_task.important = task.important; + backup_task.completed_at = task.completed_at; tasks += backup_task; } backup_group.tasks = tasks; diff --git a/src/modules/Backup/services/BackupSerializer.vala b/src/modules/Backup/services/BackupSerializer.vala index b921d25..2fed631 100644 --- a/src/modules/Backup/services/BackupSerializer.vala +++ b/src/modules/Backup/services/BackupSerializer.vala @@ -7,6 +7,7 @@ namespace Queue.Backup { public string description { get; set; default = ""; } public bool done { get; set; default = false; } public bool important { get; set; default = false; } + public string completed_at { get; set; default = ""; } } // In-memory representation of a backed-up group with its tasks. @@ -89,6 +90,8 @@ namespace Queue.Backup { builder.add_boolean_value(task.done); builder.set_member_name("important"); builder.add_boolean_value(task.important); + builder.set_member_name("completed_at"); + builder.add_string_value(task.completed_at); builder.end_object(); } builder.end_array(); @@ -131,6 +134,9 @@ namespace Queue.Backup { if (task_object.has_member("important")) { task.important = task_object.get_boolean_member("important"); } + if (task_object.has_member("completed_at")) { + task.completed_at = task_object.get_string_member("completed_at"); + } return task; } } diff --git a/src/modules/Tasks/models/Task.vala b/src/modules/Tasks/models/Task.vala index 1f8a38a..a3b0538 100644 --- a/src/modules/Tasks/models/Task.vala +++ b/src/modules/Tasks/models/Task.vala @@ -10,6 +10,7 @@ namespace Queue.Tasks { public string description { get; set; default = ""; } public bool done { get; set; } public bool important { get; set; default = false; } + public string completed_at { get; set; default = ""; } public static GLib.List for_group(Database database, int group_id) { @@ -17,7 +18,7 @@ namespace Queue.Tasks { Sqlite.Statement statement; database.connection.prepare_v2( - "SELECT id, group_id, title, description, done, important FROM tasks WHERE group_id = ? ORDER BY position, id;", + "SELECT id, group_id, title, description, done, important, completed_at FROM tasks WHERE group_id = ? ORDER BY position, id;", -1, out statement); statement.bind_int(1, group_id); @@ -30,6 +31,7 @@ namespace Queue.Tasks { task.description = statement.column_text(3); task.done = statement.column_int(4) != 0; task.important = statement.column_int(5) != 0; + task.completed_at = statement.column_text(6); tasks.append(task); } @@ -79,9 +81,25 @@ namespace Queue.Tasks { { Sqlite.Statement statement; database.connection.prepare_v2( - "UPDATE tasks SET done = ? WHERE id = ?;", -1, out statement); + "UPDATE tasks SET done = ?, completed_at = CASE WHEN ? = 1 THEN datetime('now') ELSE '' END WHERE id = ?;", + -1, out statement); + statement.bind_int(1, done ? 1 : 0); + statement.bind_int(2, done ? 1 : 0); + statement.bind_int(3, id); + statement.step(); + } + + // Restores the completion state verbatim, keeping the original + // completed_at timestamp instead of stamping the current time. Used + // when importing a backup. + public static void restore_completion(Database database, int id, bool done, string completed_at) + { + Sqlite.Statement statement; + database.connection.prepare_v2( + "UPDATE tasks SET done = ?, completed_at = ? WHERE id = ?;", -1, out statement); statement.bind_int(1, done ? 1 : 0); - statement.bind_int(2, id); + statement.bind_text(2, completed_at); + statement.bind_int(3, id); statement.step(); } From 14c2db6902ef2204f14a0197afae968504701d47 Mon Sep 17 00:00:00 2001 From: Daniel Prieto Date: Mon, 29 Jun 2026 10:52:19 +0200 Subject: [PATCH 03/13] dropdown for tasks and group actions --- src/modules/Groups/ui/GroupRow.vala | 22 ++++++++++++++++------ src/modules/Groups/ui/group-row.ui | 29 ++++++++++++++++------------- src/modules/Tasks/ui/TaskRow.vala | 24 ++++++++++++++++-------- src/modules/Tasks/ui/task-row.ui | 29 ++++++++++++++++------------- 4 files changed, 64 insertions(+), 40 deletions(-) diff --git a/src/modules/Groups/ui/GroupRow.vala b/src/modules/Groups/ui/GroupRow.vala index b420ba0..ef2268f 100644 --- a/src/modules/Groups/ui/GroupRow.vala +++ b/src/modules/Groups/ui/GroupRow.vala @@ -6,10 +6,6 @@ namespace Queue.Groups { [GtkChild] private unowned Gtk.Label name_label; - [GtkChild] - private unowned Gtk.Button edit_button; - [GtkChild] - private unowned Gtk.Button delete_button; public Group group { get; private set; } @@ -23,8 +19,22 @@ namespace Queue.Groups { // sidebar's display-wide CSS provider, refreshed when colors change. add_css_class(GroupSidebar.color_class_for(group.id)); group.bind_property("name", name_label, "label", BindingFlags.SYNC_CREATE); - edit_button.clicked.connect(() => edit_requested(group)); - delete_button.clicked.connect(() => delete_requested(group)); + install_menu_actions(); + } + + private void install_menu_actions() + { + var actions = new SimpleActionGroup(); + + var edit_action = new SimpleAction("edit", null); + edit_action.activate.connect(() => edit_requested(group)); + actions.add_action(edit_action); + + var delete_action = new SimpleAction("delete", null); + delete_action.activate.connect(() => delete_requested(group)); + actions.add_action(delete_action); + + insert_action_group("row", actions); } } } diff --git a/src/modules/Groups/ui/group-row.ui b/src/modules/Groups/ui/group-row.ui index 3399229..d0dac4f 100644 --- a/src/modules/Groups/ui/group-row.ui +++ b/src/modules/Groups/ui/group-row.ui @@ -1,6 +1,18 @@ + +
+ + Edit + row.edit + + + Delete + row.delete + +
+