diff --git a/debian/control b/debian/control index 4b1d2b2..a95febe 100644 --- a/debian/control +++ b/debian/control @@ -8,6 +8,7 @@ Build-Depends: meson, libgranite-dev, libgtk-3-dev (>= 3.22.0), libglib2.0-dev (>= 2.30.0), + libgee-0.8-dev (>= 0.8.5), libsoup2.4-dev, libjson-glib-dev Standards-Version: 3.9.3 diff --git a/meson.build b/meson.build index ba4f233..e7fbfaa 100644 --- a/meson.build +++ b/meson.build @@ -68,6 +68,7 @@ executable( dependencies: [ dependency('gtk+-3.0', version: '>=3.22.0'), dependency('glib-2.0', version: '>=2.30.0'), + dependency('gee-0.8', version: '>=0.8.5'), dependency('granite'), dependency('json-glib-1.0'), dependency('libsoup-2.4') diff --git a/src/API/Relationship.vala b/src/API/Relationship.vala index 2a1dd0f..2a1f099 100644 --- a/src/API/Relationship.vala +++ b/src/API/Relationship.vala @@ -1,4 +1,6 @@ -public class Tootle.Relationship{ +using GLib; + +public class Tootle.Relationship : Object { public int64 id; public bool following; @@ -9,11 +11,11 @@ public class Tootle.Relationship{ public bool requested; public bool domain_blocking; - public Relationship (int64 _id){ + public Relationship (int64 _id) { id = _id; } - public static Relationship parse (Json.Object obj){ + public static Relationship parse (Json.Object obj) { var id = int64.parse (obj.get_string_member ("id")); var relationship = new Relationship (id); relationship.following = obj.get_boolean_member ("following"); diff --git a/src/Accounts.vala b/src/Accounts.vala index 7fe9040..a692f32 100644 --- a/src/Accounts.vala +++ b/src/Accounts.vala @@ -1,30 +1,30 @@ using GLib; -public class Tootle.Accounts : Object{ +public class Tootle.Accounts : Object { private string dir_path; private string file_path; - public abstract signal void switched (Account? account); - public abstract signal void updated (GenericArray accounts); + public signal void switched (Account? account); + public signal void updated (GenericArray accounts); public GenericArray saved_accounts = new GenericArray (); public InstanceAccount? formal {get; set;} public Account? current {get; set;} public Accounts () { - dir_path = "%s/%s".printf (GLib.Environment.get_user_config_dir (), Tootle.app.application_id); + dir_path = "%s/%s".printf (GLib.Environment.get_user_config_dir (), app.application_id); file_path = "%s/%s".printf (dir_path, "accounts.json"); } - public void switch_account (int id){ - debug ("Switching to account #%i", id); - Tootle.settings.current_account = id; - formal = saved_accounts.@get(id); - var msg = new Soup.Message("GET", "%s/api/v1/accounts/verify_credentials".printf (Tootle.accounts.formal.instance)); - Tootle.network.queue(msg, (sess, mess) => { - try{ - var root = Tootle.network.parse (mess); + public void switch_account (int id) { + debug ("Switching to #%i", id); + settings.current_account = id; + formal = saved_accounts.@get (id); + var msg = new Soup.Message("GET", "%s/api/v1/accounts/verify_credentials".printf (accounts.formal.instance)); + network.queue (msg, (sess, mess) => { + try { + var root = network.parse (mess); current = Account.parse (root); switched (current); updated (saved_accounts); @@ -53,7 +53,7 @@ public class Tootle.Accounts : Object{ if (saved_accounts.length < 1) switched (null); else { - var id = Tootle.settings.current_account - 1; + var id = settings.current_account - 1; if (id > saved_accounts.length - 1) id = saved_accounts.length - 1; else if (id < saved_accounts.length - 1) @@ -64,7 +64,7 @@ public class Tootle.Accounts : Object{ updated (saved_accounts); if (is_empty ()) { - Tootle.window.destroy (); + window.destroy (); NewAccountDialog.open (); } } @@ -73,14 +73,14 @@ public class Tootle.Accounts : Object{ return saved_accounts.length == 0; } - public void init (){ + public void init () { save (false); load (); if (saved_accounts.length < 1) NewAccountDialog.open (); else - switch_account (Tootle.settings.current_account); + switch_account (settings.current_account); } private void save (bool overwrite = true) { diff --git a/src/Dialogs/WatchlistDialog.vala b/src/Dialogs/WatchlistDialog.vala index c8f46f2..bffe0b4 100644 --- a/src/Dialogs/WatchlistDialog.vala +++ b/src/Dialogs/WatchlistDialog.vala @@ -5,17 +5,17 @@ public class Tootle.WatchlistDialog : Gtk.Window { private static WatchlistDialog dialog; - private Gtk.HeaderBar header; - private Gtk.StackSwitcher switcher; + private HeaderBar header; + private StackSwitcher switcher; private Gtk.MenuButton button_add; - private Gtk.Stack stack; + private Stack stack; private ListStack users; private ListStack hashtags; - private Gtk.Popover popover; - private Gtk.Grid popover_grid; - private Gtk.Entry popover_entry; - private Gtk.Button popover_button; + private Popover popover; + private Grid popover_grid; + private Entry popover_entry; + private Button popover_button; private const string TIP_USERS = _("You'll be notified when toots from specific users appear in your Home timeline."); private const string TIP_HASHTAGS = _("You'll be notified when toots with specific hashtags are posted in any public timelines."); @@ -30,21 +30,21 @@ public class Tootle.WatchlistDialog : Gtk.Window { } } - private class ModelView : Gtk.ListBoxRow { - private Gtk.Box box; - private Gtk.Button button_remove; - private Gtk.Label label; + private class ModelView : ListBoxRow { + private Box box; + private Button button_remove; + private Label label; private bool is_hashtag; public ModelView (ModelItem item) { is_hashtag = item.is_hashtag; - box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0); + box = new Box (Orientation.HORIZONTAL, 0); box.margin = 6; - label = new Gtk.Label (item.name); + label = new Label (item.name); label.vexpand = true; - label.valign = Gtk.Align.CENTER; - label.justify = Gtk.Justification.LEFT; - button_remove = new Gtk.Button.from_icon_name ("list-remove-symbolic", Gtk.IconSize.BUTTON); + label.valign = Align.CENTER; + label.justify = Justification.LEFT; + button_remove = new Button.from_icon_name ("list-remove-symbolic", IconSize.BUTTON); button_remove.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); button_remove.clicked.connect (() => { watchlist.remove (label.label, is_hashtag); @@ -85,19 +85,21 @@ public class Tootle.WatchlistDialog : Gtk.Window { return new ModelView (item); } - private class ListStack : Gtk.ScrolledWindow { + private class ListStack : ScrolledWindow { public Model model; - public Gtk.ListBox list; + public ListBox list; private bool is_hashtags; public void update () { if (is_hashtags) watchlist.hashtags.@foreach (item => { model.append (new ModelItem (item, true)); + return true; }); else watchlist.users.@foreach (item => { model.append (new ModelItem (item, false)); + return true; }); list.bind_model (model, create_row); @@ -106,7 +108,7 @@ public class Tootle.WatchlistDialog : Gtk.Window { public ListStack (bool is_hashtags) { this.is_hashtags = is_hashtags; model = new Model (); - list = new Gtk.ListBox (); + list = new ListBox (); add (list); update (); } @@ -122,8 +124,8 @@ public class Tootle.WatchlistDialog : Gtk.Window { resizable = true; transient_for = window; - stack = new Gtk.Stack (); - stack.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT; + stack = new Stack (); + stack.transition_type = StackTransitionType.SLIDE_LEFT_RIGHT; stack.hexpand = true; stack.vexpand = true; @@ -134,37 +136,37 @@ public class Tootle.WatchlistDialog : Gtk.Window { stack.add_titled (hashtags, "hashtags", _("Hashtags")); stack.set_size_request (400, 300); - popover_entry = new Gtk.Entry (); + popover_entry = new Entry (); popover_entry.hexpand = true; popover_entry.secondary_icon_name = "dialog-information-symbolic"; popover_entry.secondary_icon_activatable = false; popover_entry.activate.connect (() => submit ()); - popover_button = new Gtk.Button.with_label (_("Add")); - popover_button.halign = Gtk.Align.END; + popover_button = new Button.with_label (_("Add")); + popover_button.halign = Align.END; popover_button.margin_start = 6; popover_button.clicked.connect (() => submit ()); - popover_grid = new Gtk.Grid (); + popover_grid = new Grid (); popover_grid.margin = 6; popover_grid.attach (popover_entry, 0, 0); popover_grid.attach (popover_button, 1, 0); popover_grid.show_all (); - popover = new Gtk.Popover (null); + popover = new Popover (null); popover.add (popover_grid); - button_add = new Gtk.MenuButton (); - button_add.image = new Gtk.Image.from_icon_name ("list-add-symbolic", Gtk.IconSize.BUTTON); + button_add = new MenuButton (); + button_add.image = new Image.from_icon_name ("list-add-symbolic", IconSize.BUTTON); button_add.get_style_context ().add_class (Gtk.STYLE_CLASS_SUGGESTED_ACTION); button_add.popover = popover; button_add.clicked.connect (() => set_tip ()); switcher = new StackSwitcher (); switcher.stack = stack; - switcher.halign = Gtk.Align.CENTER; + switcher.halign = Align.CENTER; - header = new Gtk.HeaderBar (); + header = new HeaderBar (); header.show_close_button = true; header.pack_start (button_add); header.set_custom_title (switcher); diff --git a/src/InstanceAccount.vala b/src/InstanceAccount.vala index 6f504c4..5e64f16 100644 --- a/src/InstanceAccount.vala +++ b/src/InstanceAccount.vala @@ -101,6 +101,7 @@ public class Tootle.InstanceAccount : GLib.Object { watchlist.users.@foreach (item => { if (item == acct || item == "@" + acct) notification (obj); + return true; }); } diff --git a/src/Views/AccountView.vala b/src/Views/AccountView.vala index 2d656de..9424d63 100644 --- a/src/Views/AccountView.vala +++ b/src/Views/AccountView.vala @@ -238,16 +238,16 @@ public class Tootle.AccountView : TimelineView { public static void open_from_id (int64 id){ var url = "%s/api/v1/accounts/%lld".printf (accounts.formal.instance, id); - var msg = new Soup.Message("GET", url); + var msg = new Soup.Message ("GET", url); msg.priority = Soup.MessagePriority.HIGH; network.queue (msg, (sess, mess) => { - try{ + try { var root = network.parse (mess); var acc = Account.parse (root); - Tootle.window.open_view (new AccountView (acc)); + window.open_view (new AccountView (acc)); } catch (GLib.Error e) { - warning ("Can't update feed"); + warning ("Can't find account"); warning (e.message); } }); @@ -258,7 +258,7 @@ public class Tootle.AccountView : TimelineView { var msg = new Soup.Message("GET", url); msg.priority = Soup.MessagePriority.HIGH; network.queue (msg, (sess, mess) => { - try{ + try { var node = network.parse_array (mess).get_element (0); var object = node.get_object (); if (object != null){ diff --git a/src/Watchlist.vala b/src/Watchlist.vala index 3dc9bbb..0ca8b22 100644 --- a/src/Watchlist.vala +++ b/src/Watchlist.vala @@ -1,13 +1,12 @@ -using Soup; using GLib; using Gdk; -using Json; +using Gee; -public class Tootle.Watchlist : GLib.Object { +public class Tootle.Watchlist : Object { - public GenericArray users = new GenericArray (); - public GenericArray hashtags = new GenericArray (); - public GenericArray notificators = new GenericArray (); + public ArrayList users = new ArrayList (); + public ArrayList hashtags = new ArrayList (); + public ArrayList notificators = new ArrayList (); construct { accounts.switched.connect (on_account_changed); @@ -16,21 +15,23 @@ public class Tootle.Watchlist : GLib.Object { public Watchlist () {} public virtual void on_account_changed (Account? account){ - if(account != null) + if (account != null) reload (); } private void reload () { info ("Reloading"); - notificators.@foreach (notificator => notificator.close ()); - notificators.remove_range (0, notificators.length); - users.remove_range (0, users.length); - hashtags.remove_range (0, hashtags.length); + notificators.@foreach (notificator => { + notificator.close (); + return true; + }); + notificators.clear (); + users.clear (); + hashtags.clear (); load (); - - info ("Watching for %i users and %i hashtags", users.length, hashtags.length); + info ("Watching for %i users and %i hashtags", users.size, hashtags.size); } private void load () { @@ -45,12 +46,18 @@ public class Tootle.Watchlist : GLib.Object { public void save () { var serialized_users = ""; - users.@foreach (item => serialized_users += item + ","); + users.@foreach (item => { + serialized_users += item + ","; + return true; + }); serialized_users = remove_last_delimiter (serialized_users); settings.watched_users = serialized_users; var serialized_hashtags = ""; - hashtags.@foreach (item => serialized_hashtags += item + ","); + hashtags.@foreach (item => { + serialized_hashtags += item + ","; + return true; + }); serialized_hashtags = remove_last_delimiter (serialized_hashtags); settings.watched_hashtags = serialized_hashtags; @@ -99,26 +106,21 @@ public class Tootle.Watchlist : GLib.Object { } public void remove (string entity, bool is_hashtag) { - int i = -1; - if (is_hashtag) - hashtags.@foreach (item => { - i++; - if (item == entity) { - var notificator = notificators.@get(i); - notificator.close (); - notificators.remove_index (i); - hashtags.remove_index (i); - info ("Removed #%s", entity); - } - }); - else - users.@foreach (item => { - i++; - if (item == entity) { - users.remove_index (i); - info ("Removed @%s", entity); - } - }); + if (entity == "") + return; + + if (is_hashtag) { + var i = hashtags.index_of (entity); + var notificator = notificators.@get(i); + notificator.close (); + notificators.remove_at (i); + hashtags.remove (entity); + info ("Removed #%s", entity); + } + else { + users.remove (entity); + info ("Removed @%s", entity); + } } } diff --git a/src/Widgets/AccountsButton.vala b/src/Widgets/AccountsButton.vala index 6395a3f..cc76db1 100644 --- a/src/Widgets/AccountsButton.vala +++ b/src/Widgets/AccountsButton.vala @@ -14,7 +14,7 @@ public class Tootle.AccountsButton : Gtk.MenuButton{ Gtk.ModelButton item_direct; Gtk.ModelButton item_watchlist; - private class AccountView : Gtk.ListBoxRow{ + private class AccountItemView : Gtk.ListBoxRow{ private Gtk.Grid grid; public Gtk.Label display_name; @@ -46,7 +46,7 @@ public class Tootle.AccountsButton : Gtk.MenuButton{ show_all (); } - public AccountView (){ + public AccountItemView (){ button.clicked.connect (() => accounts.remove (id)); } @@ -106,21 +106,23 @@ public class Tootle.AccountsButton : Gtk.MenuButton{ get_style_context ().add_class ("button_avatar"); popover = menu; - add(avatar); + add (avatar); show_all (); accounts.updated.connect (accounts_updated); accounts.switched.connect (account_switched); list.row_activated.connect (row => { - var widget = row as AccountView; + var widget = row as AccountItemView; if (widget.id == -1) { NewAccountDialog.open (); return; } - if (widget.id == Tootle.settings.current_account) - return; + if (widget.id == settings.current_account) + AccountView.open_from_id (accounts.current.id); else accounts.switch_account (widget.id); + + menu.popdown (); }); } @@ -129,14 +131,14 @@ public class Tootle.AccountsButton : Gtk.MenuButton{ int i = -1; accounts.foreach (account => { i++; - var widget = new AccountView (); + var widget = new AccountItemView (); widget.id = i; widget.display_name.label = "@"+account.username+""; widget.instance.label = account.get_pretty_instance (); list.add (widget); }); - var add_account = new AccountView (); + var add_account = new AccountItemView (); add_account.display_name.label = _("New Account"); add_account.instance.label = _("Click to add"); add_account.button.hide (); @@ -152,7 +154,7 @@ public class Tootle.AccountsButton : Gtk.MenuButton{ } private void update_selection () { - var id = Tootle.settings.current_account; + var id = settings.current_account; var row = list.get_row_at_index (id); if (row != null) list.select_row (row);