Skip to content

Commit

Permalink
CalDAV task completion support
Browse files Browse the repository at this point in the history
  • Loading branch information
alainm23 committed Jan 24, 2024
1 parent e0ee9c1 commit 2724ead
Show file tree
Hide file tree
Showing 22 changed files with 185 additions and 117 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ builddir/
build-aux/build-dir
build-aux/flatpak_build
build-aux/.flatpak-builder
build-aux/io.github.alainm23.planify.Devel.flatpak
.flatpak-builder/
subprojects/gxml

Binary file not shown.
31 changes: 12 additions & 19 deletions build-aux/io.github.alainm23.planify.Devel.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
{
"app-id" : "io.github.alainm23.planify.Devel",
"runtime" : "org.gnome.Platform",
"app-id": "io.github.alainm23.planify.Devel",
"runtime": "org.gnome.Platform",
"runtime-version": "45",
"sdk" : "org.gnome.Sdk",
"command" : "io.github.alainm23.planify.Devel",
"tags" : [
"devel"
],
"sdk": "org.gnome.Sdk",
"command": "io.github.alainm23.planify.Devel",
"tags": ["devel"],
"finish-args": [
"--device=dri",
"--share=ipc",
Expand All @@ -31,10 +29,10 @@
"*.la",
"*.a"
],
"modules" : [
"modules": [
{
"name": "intltool",
"cleanup": [ "*" ],
"cleanup": ["*"],
"sources": [
{
"type": "archive",
Expand All @@ -57,9 +55,7 @@
{
"name": "libical",
"buildsystem": "cmake-ninja",
"cleanup": [
"/lib/cmake"
],
"cleanup": ["/lib/cmake"],
"config-opts": [
"-DCMAKE_BUILD_TYPE=Release",
"-DCMAKE_INSTALL_LIBDIR=/app/lib",
Expand Down Expand Up @@ -153,13 +149,10 @@
]
},
{
"name" : "planify",
"builddir" : true,
"buildsystem" : "meson",
"config-opts" : [
"-Dtracing=true",
"-Dprofile=development"
],
"name": "planify",
"builddir": true,
"buildsystem": "meson",
"config-opts": ["-Dtracing=true", "-Dprofile=development"],
"sources": [
{
"type": "dir",
Expand Down
39 changes: 30 additions & 9 deletions core/Objects/Item.vala
Original file line number Diff line number Diff line change
Expand Up @@ -329,8 +329,8 @@ public class Objects.Item : Objects.BaseObject {
description = ical.get_description ();
}

if (Util.get_default ().find_string_value ("PRIORITY", data) != "") {
int _priority = int.parse (Util.get_default ().find_string_value ("PRIORITY", data));
if (Util.find_string_value ("PRIORITY", data) != "") {
int _priority = int.parse (Util.find_string_value ("PRIORITY", data));
if (_priority <= 0) {
priority = Constants.PRIORITY_4;
} else if (_priority >= 1 && _priority <= 4) {
Expand All @@ -345,16 +345,29 @@ public class Objects.Item : Objects.BaseObject {
}

if (!ical.get_due ().is_null_time ()) {
due.date = Util.get_default ().ical_to_date_time_local (ical.get_due ()).to_string ();
due.date = Util.ical_to_date_time_local (ical.get_due ()).to_string ();
}

string _parent_id = Util.get_default ().find_string_value ("RELATED-TO", data);
string _parent_id = Util.find_string_value ("RELATED-TO", data);
if (_parent_id != "") {
parent_id = _parent_id;
}

pinned = Util.get_default ().find_boolean_value ("X-PINNED", data);
extra_data = Util.get_default ().generate_extra_data (Util.get_default ().get_task_id_from_url (element), etag, ical.as_ical_string ());
if (ical.get_status () == ICal.PropertyStatus.COMPLETED) {
checked = true;
var completed_datetime = ical.get_first_property (ICal.PropertyKind.COMPLETED_PROPERTY);
if (completed_datetime != null) {
completed_at = Util.ical_to_date_time_local (completed_datetime.get_completed ()).to_string ();
} else {
completed_at = Util.get_default ().get_format_date (new GLib.DateTime.now_local ()).to_string ();
}
} else {
checked = false;
completed_at = "";
}

pinned = Util.find_boolean_value ("X-PINNED", data);
extra_data = Util.generate_extra_data (Util.get_task_id_from_url (element), etag, ical.as_ical_string ());
}

public void update_from_json (Json.Node node) {
Expand Down Expand Up @@ -872,7 +885,7 @@ public class Objects.Item : Objects.BaseObject {
return generator.to_data (null);
}

public string to_vtodo (bool update = false) {
public string to_vtodo () {
ICal.Component ical = new ICal.Component.vtodo ();

ical.set_uid (id);
Expand All @@ -887,10 +900,18 @@ public class Objects.Item : Objects.BaseObject {
}

if (has_due) {
var task_tz = ical.get_due ().get_timezone ();
ICal.Time new_icaltime = Util.get_default ().datetimes_to_icaltime (due.datetime, due.datetime, null);
// var task_tz = ical.get_due ().get_timezone ();
ICal.Time new_icaltime = Util.datetimes_to_icaltime (due.datetime, due.datetime, null);
ical.set_due (new_icaltime);
}

if (checked) {
ical.set_status (ICal.PropertyStatus.COMPLETED);
ical.add_property (new ICal.Property.percentcomplete (100));
ical.add_property (new ICal.Property.completed (new ICal.Time.today ()));
} else {
ical.set_status (ICal.PropertyStatus.NEEDSACTION);
}

var _priority = 0;
if (priority == Constants.PRIORITY_4) {
Expand Down
1 change: 1 addition & 0 deletions core/Objects/Section.vala
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public class Objects.Section : Objects.BaseObject {
public bool is_archived { get; set; default = false; }
public string color { get; set; default = ""; }
public string description { get; set; default = ""; }
public bool hidded { get; set; default = false; }

// Tmp
public bool activate_name_editable { get; set; default = false; }
Expand Down
49 changes: 39 additions & 10 deletions core/Services/CalDAV.vala
Original file line number Diff line number Diff line change
Expand Up @@ -250,9 +250,6 @@ public class Services.CalDAV : GLib.Object {
<x1:filter>
<x1:comp-filter name="VCALENDAR">
<x1:comp-filter name="VTODO">
<x1:prop-filter name="completed">
<x1:is-not-defined/>
</x1:prop-filter>
</x1:comp-filter>
</x1:comp-filter>
</x1:filter>
Expand Down Expand Up @@ -392,7 +389,7 @@ public class Services.CalDAV : GLib.Object {
GXml.DomHTMLCollection response = doc.get_elements_by_tag_name ("d:response");
foreach (GXml.DomElement element in response) {
Objects.Item? item = Services.Database.get_default ().get_item (
Util.get_default ().get_task_uid (element)
Util.get_task_uid (element)
);

if (item != null) {
Expand All @@ -403,9 +400,15 @@ public class Services.CalDAV : GLib.Object {
item.update_from_caldav_xml (element);
Services.Database.get_default ().update_item (item);

// TODO: Fix moved
if (old_parent_id != item.parent_id) {
Services.EventBus.get_default ().item_moved (item, old_project_id, old_section_id, old_parent_id);
}

bool old_checked = item.checked;
if (old_checked != item.checked) {
Services.Database.get_default ().checked_toggled (item, old_checked);
}
} else {
add_item_if_not_exists (element, project);
}
Expand All @@ -416,7 +419,7 @@ public class Services.CalDAV : GLib.Object {
}

private void add_item_if_not_exists (GXml.DomElement element, Objects.Project project) {
string parent_id = Util.get_default ().get_related_to_uid (element);
string parent_id = Util.get_related_to_uid (element);
if (parent_id != "") {
Objects.Item? parent_item = Services.Database.get_default ().get_item (parent_id);
if (parent_item != null) {
Expand Down Expand Up @@ -570,13 +573,10 @@ public class Services.CalDAV : GLib.Object {

var ics = update ? item.ics : "%s.ics".printf (item.id);

print ("%s\n".printf (item.to_vtodo (update)));

var url = "%s/remote.php/dav/calendars/%s/%s/%s".printf (server_url, username, item.project.id, ics);
print ("URL: %s\n".printf (url));
var message = new Soup.Message ("PUT", url);
message.request_headers.append ("Authorization", "Basic %s".printf (credential));
message.set_request_body_from_bytes ("application/xml", new Bytes (item.to_vtodo (update).data));
message.set_request_body_from_bytes ("application/xml", new Bytes (item.to_vtodo ().data));

HttpResponse response = new HttpResponse ();

Expand All @@ -585,7 +585,7 @@ public class Services.CalDAV : GLib.Object {

if (update ? message.status_code == 204 : message.status_code == 201) {
response.status = true;
item.extra_data = Util.get_default ().generate_extra_data (ics, "", item.to_vtodo (update));
item.extra_data = Util.generate_extra_data (ics, "", item.to_vtodo ());
}
} catch (Error e) {
debug (e.message);
Expand Down Expand Up @@ -623,6 +623,35 @@ public class Services.CalDAV : GLib.Object {
return response;
}

public async HttpResponse complete_item (Objects.Item item) {
var server_url = Services.Settings.get_default ().settings.get_string ("caldav-server-url");
var username = Services.Settings.get_default ().settings.get_string ("caldav-username");
var credential = Services.Settings.get_default ().settings.get_string ("caldav-credential");

var ics = item.ics;
var body = item.to_vtodo ();

var url = "%s/remote.php/dav/calendars/%s/%s/%s".printf (server_url, username, item.project.id, ics);
var message = new Soup.Message ("PUT", url);
message.request_headers.append ("Authorization", "Basic %s".printf (credential));
message.set_request_body_from_bytes ("application/xml", new Bytes (body.data));

HttpResponse response = new HttpResponse ();

try {
yield session.send_and_read_async (message, GLib.Priority.HIGH, null);

if (message.status_code == 204) {
response.status = true;
item.extra_data = Util.generate_extra_data (ics, "", body);
}
} catch (Error e) {
debug (e.message);
}

return response;
}

public void remove_items () {
Services.Settings.get_default ().settings.set_string ("caldav-server-url", "");
Services.Settings.get_default ().settings.set_string ("caldav-username", "");
Expand Down
21 changes: 13 additions & 8 deletions core/Services/Database.vala
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,8 @@ public class Services.Database : GLib.Object {
* - Add extra data column to Items
*/

add_text_column ("Items", "extra_data", "");
add_text_column ("Items", "extra_data", "");
add_int_column ("Sections", "hidded", 0);
}

private void create_tables () {
Expand Down Expand Up @@ -252,6 +253,7 @@ public class Services.Database : GLib.Object {
is_archived INTEGER,
color TEXT,
description TEXT,
hidded INTEGER,
FOREIGN KEY (project_id) REFERENCES Projects (id) ON DELETE CASCADE
);
""";
Expand Down Expand Up @@ -789,8 +791,7 @@ public class Services.Database : GLib.Object {
}
}

public Objects.Label get_label_by_name (string name, bool lowercase = false, BackendType backend_type) {
Objects.Label? return_value = null;
public Objects.Label? get_label_by_name (string name, bool lowercase = false, BackendType backend_type) {
lock (_labels) {
string compare_name = lowercase ? name.down () : name;

Expand Down Expand Up @@ -901,9 +902,9 @@ public class Services.Database : GLib.Object {

sql = """
INSERT OR IGNORE INTO Sections (id, name, archived_at, added_at, project_id, section_order,
collapsed, is_deleted, is_archived, color, description)
collapsed, is_deleted, is_archived, color, description, hidded)
VALUES ($id, $name, $archived_at, $added_at, $project_id, $section_order,
$collapsed, $is_deleted, $is_archived, $color, $description);
$collapsed, $is_deleted, $is_archived, $color, $description, $hidded);
""";

db.prepare_v2 (sql, sql.length, out stmt);
Expand All @@ -918,6 +919,7 @@ public class Services.Database : GLib.Object {
set_parameter_bool (stmt, "$is_archived", section.is_archived);
set_parameter_str (stmt, "$color", section.color);
set_parameter_str (stmt, "$description", section.description);
set_parameter_bool (stmt, "$hidded", section.hidded);

if (stmt.step () == Sqlite.DONE) {
sections.add (section);
Expand Down Expand Up @@ -985,6 +987,7 @@ public class Services.Database : GLib.Object {
return_value.is_archived = get_parameter_bool (stmt, 8);
return_value.color = stmt.column_text (9);
return_value.description = stmt.column_text (10);
return_value.hidded = get_parameter_bool (stmt, 11);
return return_value;
}

Expand Down Expand Up @@ -1016,8 +1019,9 @@ public class Services.Database : GLib.Object {

sql = """
UPDATE Sections SET name=$name, archived_at=$archived_at, added_at=$added_at,
project_id=$project_id, section_order=$section_order, collapsed=$collapsed,
is_deleted=$is_deleted, is_archived=$is_archived, color=$color, description=$description
project_id=$project_id, section_order=$section_order, collapsed=$collapsed,
is_deleted=$is_deleted, is_archived=$is_archived, color=$color, description=$description,
hidded=$hidded
WHERE id=$id;
""";

Expand All @@ -1032,6 +1036,7 @@ public class Services.Database : GLib.Object {
set_parameter_bool (stmt, "$is_archived", section.is_archived);
set_parameter_str (stmt, "$color", section.color);
set_parameter_str (stmt, "$description", section.description);
set_parameter_bool (stmt, "$hidded", section.hidded);
set_parameter_str (stmt, "$id", section.id);

if (stmt.step () == Sqlite.DONE) {
Expand Down Expand Up @@ -2001,7 +2006,7 @@ public class Services.Database : GLib.Object {
warning ("Error: %d: %s", db.errcode (), db.errmsg ());
}

stmt.reset ();
stmt.reset();
}

public void clear_queue () {
Expand Down
2 changes: 1 addition & 1 deletion core/Services/Todoist.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1391,7 +1391,7 @@ public class HttpResponse {

public void from_error_xml (GXml.DomDocument doc, int error_code) {
status = false;
error_code = error_code;
this.error_code = error_code;
http_code = error_code;
error = doc.get_elements_by_tag_name ("o:hint").get_element (0).text_content;
}
Expand Down
4 changes: 2 additions & 2 deletions core/Util/Util.vala
Original file line number Diff line number Diff line change
Expand Up @@ -1143,7 +1143,7 @@ We hope you’ll enjoy using Planify!""");
GXml.DomElement propstat = element.get_elements_by_tag_name ("d:propstat").get_element (0);
GXml.DomElement prop = propstat.get_elements_by_tag_name ("d:prop").get_element (0);
string data = prop.get_elements_by_tag_name ("cal:calendar-data").get_element (0).text_content;
string etag = prop.get_elements_by_tag_name ("d:getetag").get_element (0).text_content;
// string etag = prop.get_elements_by_tag_name ("d:getetag").get_element (0).text_content;

ICal.Component ical = new ICal.Component.from_string (data);
return ical.get_uid ();
Expand All @@ -1153,7 +1153,7 @@ We hope you’ll enjoy using Planify!""");
GXml.DomElement propstat = element.get_elements_by_tag_name ("d:propstat").get_element (0);
GXml.DomElement prop = propstat.get_elements_by_tag_name ("d:prop").get_element (0);
string data = prop.get_elements_by_tag_name ("cal:calendar-data").get_element (0).text_content;
return Util.get_default ().find_string_value ("RELATED-TO", data);
return Util.find_string_value ("RELATED-TO", data);
}

public static string find_string_value (string key, string data) {
Expand Down
5 changes: 5 additions & 0 deletions data/resources/stylesheet/stylesheet.css
Original file line number Diff line number Diff line change
Expand Up @@ -587,4 +587,9 @@ checkbutton.theme-selector radio:checked {

.banner-text {
color: #333;
}

.active-switch slider {
min-height: 16px;
min-width: 16px;
}
3 changes: 1 addition & 2 deletions src/Dialogs/ManageSectionOrder.vala
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
public class Dialogs.ManageSectionOrder : Adw.Window {
public Objects.Project project { get; construct; }
private Gtk.ListBox listbox;
private Gtk.DropControllerMotion drop_motion_ctrl;
private Widgets.ScrolledWindow scrolled_window;

public ManageSectionOrder (Objects.Project project) {
Expand All @@ -31,7 +30,7 @@ public class Dialogs.ManageSectionOrder : Adw.Window {
deletable: true,
resizable: true,
modal: true,
title: _("Manage Section Order"),
title: _("Manage Sections"),
width_request: 320,
height_request: 450,
transient_for: (Gtk.Window) Planify.instance.main_window
Expand Down
Loading

0 comments on commit 2724ead

Please sign in to comment.