Introduce Widgetizable interface
This commit is contained in:
parent
d24e10ace2
commit
82e2f93bc8
|
@ -58,6 +58,8 @@ executable(
|
||||||
'src/API/Notification.vala',
|
'src/API/Notification.vala',
|
||||||
'src/API/NotificationType.vala',
|
'src/API/NotificationType.vala',
|
||||||
'src/API/Attachment.vala',
|
'src/API/Attachment.vala',
|
||||||
|
'src/API/Conversation.vala',
|
||||||
|
'src/Widgets/Widgetizable.vala',
|
||||||
'src/Widgets/Avatar.vala',
|
'src/Widgets/Avatar.vala',
|
||||||
'src/Widgets/AccountsButton.vala',
|
'src/Widgets/AccountsButton.vala',
|
||||||
'src/Widgets/RichLabel.vala',
|
'src/Widgets/RichLabel.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 ();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -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 int64 id { get; construct set; }
|
||||||
public Account account { 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 () {
|
public Json.Node? serialize () {
|
||||||
var builder = new Json.Builder ();
|
var builder = new Json.Builder ();
|
||||||
builder.begin_object ();
|
builder.begin_object ();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
using Gee;
|
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 int64 id { get; construct set; } //TODO: IDs are no longer guaranteed to be numbers. Replace with strings.
|
||||||
public API.Account account { get; construct set; }
|
public API.Account account { get; construct set; }
|
||||||
|
@ -115,6 +114,13 @@ public class Tootle.API.Status : GLib.Object {
|
||||||
content = Html.remove_tags (account.note);
|
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 () {
|
public Json.Node? serialize () {
|
||||||
var builder = new Json.Builder ();
|
var builder = new Json.Builder ();
|
||||||
builder.begin_object ();
|
builder.begin_object ();
|
||||||
|
|
|
@ -6,7 +6,8 @@ namespace Tootle {
|
||||||
public errordomain Oopsie {
|
public errordomain Oopsie {
|
||||||
USER,
|
USER,
|
||||||
PARSING,
|
PARSING,
|
||||||
INSTANCE
|
INSTANCE,
|
||||||
|
INTERNAL
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Application app;
|
public static Application app;
|
||||||
|
|
|
@ -4,7 +4,8 @@ public class Tootle.Views.Conversations : Views.Timeline {
|
||||||
Object (
|
Object (
|
||||||
url: "/api/v1/conversations",
|
url: "/api/v1/conversations",
|
||||||
label: _("Conversations"),
|
label: _("Conversations"),
|
||||||
icon: "mail-send-symbolic"
|
icon: API.Visibility.DIRECT.get_icon (),
|
||||||
|
accepts: typeof (API.Conversation)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
|
||||||
label: _("Notifications"),
|
label: _("Notifications"),
|
||||||
icon: Desktop.fallback_icon ("notification-symbolic", "preferences-system-notifications-symbolic", "user-invisible-symbolic")
|
icon: Desktop.fallback_icon ("notification-symbolic", "preferences-system-notifications-symbolic", "user-invisible-symbolic")
|
||||||
);
|
);
|
||||||
|
accepts = typeof (API.Notification);
|
||||||
on_notification.connect (add_notification);
|
on_notification.connect (add_notification);
|
||||||
on_status_added.disconnect (add_status);
|
on_status_added.disconnect (add_status);
|
||||||
}
|
}
|
||||||
|
@ -41,20 +42,15 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
|
||||||
accounts.save ();
|
accounts.save ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override GLib.Object? to_entity (Json.Object? json) {
|
public override GLib.Object to_entity (Json.Node node) throws Oopsie {
|
||||||
if (json != null)
|
if (node == null)
|
||||||
return new API.Notification (json);
|
throw new Oopsie.PARSING ("Received null Json.Node");
|
||||||
else
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public override Widget? widgetize (GLib.Object? entity) {
|
var obj = node.get_object ();
|
||||||
var n = entity as API.Notification;
|
if (obj == null)
|
||||||
if (n == null)
|
throw new Oopsie.PARSING ("Received Json.Node is not a Json.Object!");
|
||||||
return null;
|
|
||||||
|
|
||||||
var w = new Widgets.Notification (n);
|
return new API.Notification (obj);
|
||||||
return w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void on_account_changed (InstanceAccount? acc) {
|
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 () {
|
public override bool request () {
|
||||||
if (account != null) {
|
if (account != null) {
|
||||||
account.cached_notifications.@foreach (n => {
|
account.cached_notifications.@foreach (n => {
|
||||||
append (widgetize (n));
|
append (n.to_widget ());
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -86,7 +82,7 @@ public class Tootle.Views.Notifications : Views.Timeline, IAccountListener, IStr
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_notification (API.Notification n) {
|
void add_notification (API.Notification n) {
|
||||||
prepend (widgetize (n));
|
prepend (n.to_widget ());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,11 +156,12 @@ public class Tootle.Views.Profile : Views.Timeline {
|
||||||
return base.append_params (req);
|
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)
|
if (posts_tab.active)
|
||||||
return new API.Status (json);
|
return new API.Status (obj);
|
||||||
else {
|
else {
|
||||||
var account = new API.Account (json);
|
var account = new API.Account (obj);
|
||||||
return new API.Status.from_account (account);
|
return new API.Status.from_account (account);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba
|
||||||
|
|
||||||
public string url { get; construct set; }
|
public string url { get; construct set; }
|
||||||
public bool is_public { get; construct set; default = false; }
|
public bool is_public { get; construct set; default = false; }
|
||||||
|
public Type accepts { get; set; default = typeof (API.Status); }
|
||||||
|
|
||||||
protected InstanceAccount? account = null;
|
protected InstanceAccount? account = null;
|
||||||
|
|
||||||
|
@ -29,21 +30,15 @@ public class Tootle.Views.Timeline : IAccountListener, IStreamListener, Views.Ba
|
||||||
return status.is_owned ();
|
return status.is_owned ();
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual GLib.Object? to_entity (Json.Object? json) {
|
public virtual GLib.Object to_entity (Json.Node node) throws Oopsie {
|
||||||
return new API.Status (json);
|
if (node == null)
|
||||||
}
|
throw new Oopsie.PARSING ("Received null Json.Node");
|
||||||
|
|
||||||
public virtual Widget? widgetize (GLib.Object? entity) {
|
var obj = node.get_object ();
|
||||||
var status = entity as API.Status;
|
if (obj == null)
|
||||||
if (status == null)
|
throw new Oopsie.PARSING ("Received Json.Node is not a Json.Object!");
|
||||||
return null;
|
|
||||||
|
|
||||||
var w = new Widgets.Status (status);
|
return new API.Status (obj);
|
||||||
w.button_press_event.connect (w.open);
|
|
||||||
if (!is_status_owned (status))
|
|
||||||
w.avatar.button_press_event.connect (w.on_avatar_clicked);
|
|
||||||
|
|
||||||
return w;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void prepend (Widget? w) {
|
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) {
|
public virtual void append (Widget? w, bool first = false) {
|
||||||
if (w == null)
|
if (w == null) {
|
||||||
|
warning ("Attempted to add an empty widget");
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (first)
|
if (first)
|
||||||
content_list.prepend (w);
|
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 ()))
|
append_params (new Request.GET (get_req_url ()))
|
||||||
.with_account (account)
|
.with_account (account)
|
||||||
.then_parse_array ((node, msg) => {
|
.then_parse_array ((node, msg) => {
|
||||||
var obj = node.get_object ();
|
try {
|
||||||
if (obj == null)
|
var e = to_entity (node);
|
||||||
warning ("Received invalid Json.Object");
|
var w = e as Widgetizable;
|
||||||
else {
|
append (w.to_widget ());
|
||||||
var entity = to_entity (obj);
|
}
|
||||||
if (entity == null)
|
catch (Error e) {
|
||||||
warning ("Can't convert Json.Object to required entity");
|
warning (@"Timeline item parse error: $(e.message)");
|
||||||
else
|
|
||||||
append (widgetize (entity));
|
|
||||||
}
|
}
|
||||||
get_pages (msg.response_headers.get_one ("Link"));
|
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;
|
allow_update = settings.public_live_updates;
|
||||||
|
|
||||||
if (settings.live_updates && allow_update)
|
if (settings.live_updates && allow_update)
|
||||||
prepend (widgetize (status));
|
prepend (status.to_widget ());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void remove_status (int64 id) {
|
protected virtual void remove_status (int64 id) {
|
||||||
|
|
|
@ -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 = "<a href=\"%s\">@%s</a>".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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -135,6 +135,7 @@ public class Tootle.Widgets.Status : EventBox {
|
||||||
}
|
}
|
||||||
|
|
||||||
menu_button.clicked.connect (open_menu);
|
menu_button.clicked.connect (open_menu);
|
||||||
|
avatar.button_press_event.connect (on_avatar_clicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Status (API.Status status, API.NotificationType? _kind = null) {
|
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);
|
var view = new Views.Profile (status.formal.account);
|
||||||
return window.open_view (view);
|
return window.open_view (view);
|
||||||
}
|
}
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool open (EventButton ev) {
|
public bool open (EventButton ev) {
|
||||||
|
|
|
@ -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!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue