From 82e2f93bc8d72f97e6b23f5400f12f912fac3b86 Mon Sep 17 00:00:00 2001 From: Bleak Grey Date: Wed, 3 Jun 2020 18:06:11 +0300 Subject: [PATCH] Introduce Widgetizable interface --- meson.build | 2 ++ src/API/Conversation.vala | 10 ++++++++ src/API/Notification.vala | 6 ++++- src/API/Status.vala | 10 ++++++-- src/Application.vala | 3 ++- src/Views/Conversations.vala | 3 ++- src/Views/Notifications.vala | 24 ++++++++----------- src/Views/Profile.vala | 7 +++--- src/Views/Timeline.vala | 43 ++++++++++++++++------------------- src/Widgets/Account.vala | 40 -------------------------------- src/Widgets/Status.vala | 3 ++- src/Widgets/Widgetizable.vala | 7 ++++++ 12 files changed, 71 insertions(+), 87 deletions(-) delete mode 100644 src/Widgets/Account.vala create mode 100644 src/Widgets/Widgetizable.vala diff --git a/meson.build b/meson.build index 3fd22de..3bca961 100644 --- a/meson.build +++ b/meson.build @@ -58,6 +58,8 @@ executable( 'src/API/Notification.vala', 'src/API/NotificationType.vala', 'src/API/Attachment.vala', + 'src/API/Conversation.vala', + 'src/Widgets/Widgetizable.vala', 'src/Widgets/Avatar.vala', 'src/Widgets/AccountsButton.vala', 'src/Widgets/RichLabel.vala', diff --git a/src/API/Conversation.vala b/src/API/Conversation.vala index e69de29..0f8a1b7 100644 --- a/src/API/Conversation.vala +++ b/src/API/Conversation.vala @@ -0,0 +1,10 @@ +public class Tootle.API.Conversation : GLib.Object, Json.Serializable, Widgetizable { + + public string id { get; construct set; } + public bool unread { get; set; default = false; } + + public Conversation () { + GLib.Object (); + } + +} diff --git a/src/API/Notification.vala b/src/API/Notification.vala index 572a826..6586770 100644 --- a/src/API/Notification.vala +++ b/src/API/Notification.vala @@ -1,4 +1,4 @@ -public class Tootle.API.Notification : GLib.Object { +public class Tootle.API.Notification : GLib.Object, Widgetizable { public int64 id { get; construct set; } public Account account { get; construct set; } @@ -27,6 +27,10 @@ public class Tootle.API.Notification : GLib.Object { ); } + public override Gtk.Widget to_widget () { + return new Widgets.Notification (this); + } + public Json.Node? serialize () { var builder = new Json.Builder (); builder.begin_object (); diff --git a/src/API/Status.vala b/src/API/Status.vala index e1ec5ae..bc7c15c 100644 --- a/src/API/Status.vala +++ b/src/API/Status.vala @@ -1,7 +1,6 @@ using Gee; -public class Tootle.API.Status : GLib.Object { - +public class Tootle.API.Status : GLib.Object, Widgetizable { public int64 id { get; construct set; } //TODO: IDs are no longer guaranteed to be numbers. Replace with strings. public API.Account account { get; construct set; } @@ -115,6 +114,13 @@ public class Tootle.API.Status : GLib.Object { content = Html.remove_tags (account.note); } + public override Gtk.Widget to_widget () { + var w = new Widgets.Status (this); + w.button_press_event.connect (w.open); + + return w; + } + public Json.Node? serialize () { var builder = new Json.Builder (); builder.begin_object (); diff --git a/src/Application.vala b/src/Application.vala index 908776f..ee8c9c1 100644 --- a/src/Application.vala +++ b/src/Application.vala @@ -6,7 +6,8 @@ namespace Tootle { public errordomain Oopsie { USER, PARSING, - INSTANCE + INSTANCE, + INTERNAL } public static Application app; diff --git a/src/Views/Conversations.vala b/src/Views/Conversations.vala index 55c7c23..9cff7eb 100644 --- a/src/Views/Conversations.vala +++ b/src/Views/Conversations.vala @@ -4,7 +4,8 @@ public class Tootle.Views.Conversations : Views.Timeline { Object ( url: "/api/v1/conversations", label: _("Conversations"), - icon: "mail-send-symbolic" + icon: API.Visibility.DIRECT.get_icon (), + accepts: typeof (API.Conversation) ); } diff --git a/src/Views/Notifications.vala b/src/Views/Notifications.vala index 407ff84..c289a91 100644 --- a/src/Views/Notifications.vala +++ b/src/Views/Notifications.vala @@ -11,6 +11,7 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr label: _("Notifications"), icon: Desktop.fallback_icon ("notification-symbolic", "preferences-system-notifications-symbolic", "user-invisible-symbolic") ); + accepts = typeof (API.Notification); on_notification.connect (add_notification); on_status_added.disconnect (add_status); } @@ -41,20 +42,15 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr accounts.save (); } - public override GLib.Object? to_entity (Json.Object? json) { - if (json != null) - return new API.Notification (json); - else - return null; - } + public override GLib.Object to_entity (Json.Node node) throws Oopsie { + if (node == null) + throw new Oopsie.PARSING ("Received null Json.Node"); - public override Widget? widgetize (GLib.Object? entity) { - var n = entity as API.Notification; - if (n == null) - return null; + var obj = node.get_object (); + if (obj == null) + throw new Oopsie.PARSING ("Received Json.Node is not a Json.Object!"); - var w = new Widgets.Notification (n); - return w; + return new API.Notification (obj); } public override void on_account_changed (InstanceAccount? acc) { @@ -72,7 +68,7 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr public override bool request () { if (account != null) { account.cached_notifications.@foreach (n => { - append (widgetize (n)); + append (n.to_widget ()); return true; }); } @@ -86,7 +82,7 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr } void add_notification (API.Notification n) { - prepend (widgetize (n)); + prepend (n.to_widget ()); } } diff --git a/src/Views/Profile.vala b/src/Views/Profile.vala index bb00d6d..a84859d 100644 --- a/src/Views/Profile.vala +++ b/src/Views/Profile.vala @@ -156,11 +156,12 @@ public class Tootle.Views.Profile : Views.Timeline { return base.append_params (req); } - public override GLib.Object? to_entity (Json.Object? json) { + public override GLib.Object to_entity (Json.Node node) { + var obj = node.get_object (); if (posts_tab.active) - return new API.Status (json); + return new API.Status (obj); else { - var account = new API.Account (json); + var account = new API.Account (obj); return new API.Status.from_account (account); } } diff --git a/src/Views/Timeline.vala b/src/Views/Timeline.vala index 25a0a3e..bcffb74 100644 --- a/src/Views/Timeline.vala +++ b/src/Views/Timeline.vala @@ -5,6 +5,7 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba public string url { get; construct set; } public bool is_public { get; construct set; default = false; } + public Type accepts { get; set; default = typeof (API.Status); } protected InstanceAccount? account = null; @@ -29,21 +30,15 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba return status.is_owned (); } - public virtual GLib.Object? to_entity (Json.Object? json) { - return new API.Status (json); - } + public virtual GLib.Object to_entity (Json.Node node) throws Oopsie { + if (node == null) + throw new Oopsie.PARSING ("Received null Json.Node"); - public virtual Widget? widgetize (GLib.Object? entity) { - var status = entity as API.Status; - if (status == null) - return null; + var obj = node.get_object (); + if (obj == null) + throw new Oopsie.PARSING ("Received Json.Node is not a Json.Object!"); - var w = new Widgets.Status (status); - w.button_press_event.connect (w.open); - if (!is_status_owned (status)) - w.avatar.button_press_event.connect (w.on_avatar_clicked); - - return w; + return new API.Status (obj); } public void prepend (Widget? w) { @@ -51,8 +46,10 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba } public virtual void append (Widget? w, bool first = false) { - if (w == null) + if (w == null) { + warning ("Attempted to add an empty widget"); return; + } if (first) content_list.prepend (w); @@ -105,15 +102,13 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba append_params (new Request.GET (get_req_url ())) .with_account (account) .then_parse_array ((node, msg) => { - var obj = node.get_object (); - if (obj == null) - warning ("Received invalid Json.Object"); - else { - var entity = to_entity (obj); - if (entity == null) - warning ("Can't convert Json.Object to required entity"); - else - append (widgetize (entity)); + try { + var e = to_entity (node); + var w = e as Widgetizable; + append (w.to_widget ()); + } + catch (Error e) { + warning (@"Timeline item parse error: $(e.message)"); } get_pages (msg.response_headers.get_one ("Link")); }) @@ -154,7 +149,7 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba allow_update = settings.public_live_updates; if (settings.live_updates && allow_update) - prepend (widgetize (status)); + prepend (status.to_widget ()); } protected virtual void remove_status (int64 id) { diff --git a/src/Widgets/Account.vala b/src/Widgets/Account.vala deleted file mode 100644 index 0e7b9c1..0000000 --- a/src/Widgets/Account.vala +++ /dev/null @@ -1,40 +0,0 @@ -using Gdk; - -public class Tootle.Widgets.Account : Widgets.Status { - - public Account (API.Account account) { - var status = new API.Status (-1); - status.account = account; - //status.url = account.url; - //status.content = "@%s".printf (account.url, account.acct); - //status.created_at = account.created_at; - - base (status); - - //counters.visible = false; - //title_acct.visible = false; - //content_label.margin_bottom = 12; - } - - protected override bool on_clicked (EventButton ev) { - if (ev.button == 1) - return on_avatar_clicked (ev); - return false; - } - - public override bool open_menu (uint button, uint32 time) { - var menu = new Gtk.Menu (); - - var item_open_link = new Gtk.MenuItem.with_label (_("Open in Browser")); - item_open_link.activate.connect (() => Desktop.open_uri (status.url)); - var item_copy_link = new Gtk.MenuItem.with_label (_("Copy Link")); - item_copy_link.activate.connect (() => Desktop.copy (status.url)); - menu.add (item_open_link); - menu.add (item_copy_link); - - menu.show_all (); - menu.popup_at_pointer (); - return true; - } - -} diff --git a/src/Widgets/Status.vala b/src/Widgets/Status.vala index d9f4690..9addae5 100644 --- a/src/Widgets/Status.vala +++ b/src/Widgets/Status.vala @@ -135,6 +135,7 @@ public class Tootle.Widgets.Status : EventBox { } menu_button.clicked.connect (open_menu); + avatar.button_press_event.connect (on_avatar_clicked); } public Status (API.Status status, API.NotificationType? _kind = null) { @@ -166,7 +167,7 @@ public class Tootle.Widgets.Status : EventBox { var view = new Views.Profile (status.formal.account); return window.open_view (view); } - return false; + return true; } public bool open (EventButton ev) { diff --git a/src/Widgets/Widgetizable.vala b/src/Widgets/Widgetizable.vala new file mode 100644 index 0000000..0b71065 --- /dev/null +++ b/src/Widgets/Widgetizable.vala @@ -0,0 +1,7 @@ +public interface Tootle.Widgetizable : GLib.Object { + + public virtual Gtk.Widget to_widget () throws Oopsie { + throw new Tootle.Oopsie.INTERNAL ("Widgetizable didn't provide a Widget!"); + } + +}