From 02f918d6377f78481de1b9d9485bfb4fa183aaaa Mon Sep 17 00:00:00 2001 From: Bleak Grey Date: Thu, 9 Sep 2021 14:47:11 +0300 Subject: [PATCH] InstanceAccount: Register places (#328) --- meson.build | 1 + src/Services/Accounts/InstanceAccount.vala | 15 +- src/Services/Accounts/Mastodon/Account.vala | 195 ++++++++++---------- src/Services/Accounts/Places.vala | 13 ++ src/Views/Main.vala | 1 + src/Views/Sidebar.vala | 86 ++++----- 6 files changed, 162 insertions(+), 149 deletions(-) create mode 100644 src/Services/Accounts/Places.vala diff --git a/meson.build b/meson.build index 7993eb6..c5c7370 100644 --- a/meson.build +++ b/meson.build @@ -36,6 +36,7 @@ sources = files( 'src/Utils/DateTime.vala', 'src/Services/Accounts/InstanceAccount.vala', 'src/Services/Accounts/AccountStore.vala', + 'src/Services/Accounts/Places.vala', 'src/Services/Accounts/SecretAccountStore.vala', 'src/Services/Accounts/AccountHolder.vala', 'src/Services/Accounts/Mastodon/Account.vala', diff --git a/src/Services/Accounts/InstanceAccount.vala b/src/Services/Accounts/InstanceAccount.vala index 79c28e7..ab04dfa 100644 --- a/src/Services/Accounts/InstanceAccount.vala +++ b/src/Services/Accounts/InstanceAccount.vala @@ -14,6 +14,10 @@ public class Tootle.InstanceAccount : API.Account, Streamable { public string? access_token { get; set; } public Error? error { get; set; } //TODO: use this field when server invalidates the auth token + public GLib.ListStore known_places = new GLib.ListStore (typeof (Place)); + + public HashMap type_overrides = new HashMap (); + public new string handle { owned get { return @"@$username@$domain"; } } @@ -26,8 +30,6 @@ public class Tootle.InstanceAccount : API.Account, Streamable { } } - public HashMap type_overrides = new HashMap (); - public virtual signal void activated () {} public virtual signal void deactivated () {} public virtual signal void added () { @@ -41,8 +43,9 @@ public class Tootle.InstanceAccount : API.Account, Streamable { construct { - construct_streamable (); - stream_event[EVENT_NOTIFICATION].connect (on_notification_event); + this.construct_streamable (); + this.stream_event[EVENT_NOTIFICATION].connect (on_notification_event); + this.register_known_places (this.known_places); } ~InstanceAccount () { destruct_streamable (); @@ -110,13 +113,13 @@ public class Tootle.InstanceAccount : API.Account, Streamable { return entity; } - public virtual void populate_user_menu (GLib.ListStore model) {} - public virtual void describe_kind (string kind, out string? icon, out string? descr, API.Account account) { icon = null; descr = null; } + public virtual void register_known_places (GLib.ListStore places) {} + // Notifications diff --git a/src/Services/Accounts/Mastodon/Account.vala b/src/Services/Accounts/Mastodon/Account.vala index 27a6272..04b7fcf 100644 --- a/src/Services/Accounts/Mastodon/Account.vala +++ b/src/Services/Accounts/Mastodon/Account.vala @@ -2,13 +2,13 @@ public class Tootle.Mastodon.Account : InstanceAccount { public const string BACKEND = "Mastodon"; - public const string KIND_MENTION = "mention"; - public const string KIND_REBLOG = "reblog"; - public const string KIND_FAVOURITE = "favourite"; - public const string KIND_FOLLOW = "follow"; - public const string KIND_POLL = "poll"; - public const string KIND_FOLLOW_REQUEST = "__follow-request"; - public const string KIND_REMOTE_REBLOG = "__remote-reblog"; + public const string KIND_MENTION = "mention"; + public const string KIND_REBLOG = "reblog"; + public const string KIND_FAVOURITE = "favourite"; + public const string KIND_FOLLOW = "follow"; + public const string KIND_POLL = "poll"; + public const string KIND_FOLLOW_REQUEST = "__follow-request"; + public const string KIND_REMOTE_REBLOG = "__remote-reblog"; class Test : AccountStore.BackendTest { public override string? get_backend (Json.Object obj) { @@ -25,19 +25,65 @@ public class Tootle.Mastodon.Account : InstanceAccount { }); } + public static Place PLACE_NOTIFICATIONS = new Place () { + title = _("Notifications"), + icon = "bell-symbolic", + open_func = win => { + win.open_view (new Views.Notifications ()); + } + }; + public static Place PLACE_MESSAGES = new Place () { + title = _("Direct Messages"), + icon = "mail-unread-symbolic", + open_func = (win) => { + win.open_view (new Views.Conversations ()); + } + }; - public Views.Sidebar.Item notifications_item; + public static Place PLACE_BOOKMARKS = new Place () { + title = _("Bookmarks"), + icon = "user-bookmarks-symbolic", + open_func = (win) => { + win.open_view (new Views.Bookmarks ()); + } + }; - construct { - notifications_item = new Views.Sidebar.Item () { - label = "Notifications", - icon = "bell-symbolic", - on_activated = () => { - app.main_window.open_view (new Views.Notifications ()); - } - }; - bind_property ("unread_count", notifications_item, "badge", BindingFlags.SYNC_CREATE); + public static Place PLACE_FAVORITES = new Place () { + title = _("Favorites"), + icon = "non-starred-symbolic", + open_func = (win) => { + win.open_view (new Views.Favorites ()); + } + }; + + public static Place PLACE_LISTS = new Place () { + title = _("Lists"), + icon = "view-list-symbolic", + open_func = (win) => { + win.open_view (new Views.Lists ()); + } + }; + + public static Place PLACE_SEARCH = new Place () { + title = _("Search"), + icon = "system-search-symbolic", + open_func = (win) => { + win.open_view (new Views.Search ()); + } + }; + + public override void register_known_places (GLib.ListStore places) { + places.append (PLACE_NOTIFICATIONS); + places.append (PLACE_MESSAGES); + places.append (PLACE_BOOKMARKS); + places.append (PLACE_FAVORITES); + places.append (PLACE_LISTS); + places.append (PLACE_SEARCH); + } + + construct { + // bind_property ("unread_count", notifications_item, "badge", BindingFlags.SYNC_CREATE); // Populate possible visibility variants set_visibility (new Visibility () { @@ -64,86 +110,43 @@ public class Tootle.Mastodon.Account : InstanceAccount { icon_name = "mail-unread-symbolic", description = _("Post to mentioned users only") }); - } - - public override void populate_user_menu (GLib.ListStore model) { - // model.append (new Views.Sidebar.Item () { - // label = "Timelines", - // icon = "user-home-symbolic" - // }); - model.append (notifications_item); - model.append (new Views.Sidebar.Item () { - label = "Direct Messages", - icon = "mail-unread-symbolic", - on_activated = () => { - app.main_window.open_view (new Views.Conversations ()); - } - }); - model.append (new Views.Sidebar.Item () { - label = "Bookmarks", - icon = "user-bookmarks-symbolic", - on_activated = () => { - app.main_window.open_view (new Views.Bookmarks ()); - } - }); - model.append (new Views.Sidebar.Item () { - label = "Favorites", - icon = "non-starred-symbolic", - on_activated = () => { - app.main_window.open_view (new Views.Favorites ()); - } - }); - model.append (new Views.Sidebar.Item () { - label = "Lists", - icon = "view-list-symbolic", - on_activated = () => { - app.main_window.open_view (new Views.Lists ()); - } - }); - model.append (new Views.Sidebar.Item () { - label = "Search", - icon = "system-search-symbolic", - on_activated = () => { - app.main_window.open_view (new Views.Search ()); - } - }); } - public override void describe_kind (string kind, out string? icon, out string? descr, API.Account account) { - switch (kind) { - case KIND_MENTION: - icon = "user-available-symbolic"; - descr = _("%s mentioned you").printf (account.url, account.display_name); - break; - case KIND_REBLOG: - icon = "media-playlist-repeat-symbolic"; - descr = _("%s boosted your status").printf (account.url, account.display_name); - break; - case KIND_REMOTE_REBLOG: - icon = "media-playlist-repeat-symbolic"; - descr = _("%s boosted").printf (account.url, account.display_name); - break; - case KIND_FAVOURITE: - icon = "starred-symbolic"; - descr = _("%s favorited your status").printf (account.url, account.display_name); - break; - case KIND_FOLLOW: - icon = "contact-new-symbolic"; - descr = _("%s now follows you").printf (account.url, account.display_name); - break; - case KIND_FOLLOW_REQUEST: - icon = "contact-new-symbolic"; - descr = _("%s wants to follow you").printf (account.url, account.display_name); - break; - case KIND_POLL: - icon = "emblem-default-symbolic"; - descr = _("Poll results"); - break; - default: - icon = null; - descr = null; - break; - } - } + public override void describe_kind (string kind, out string? icon, out string? descr, API.Account account) { + switch (kind) { + case KIND_MENTION: + icon = "user-available-symbolic"; + descr = _("%s mentioned you").printf (account.url, account.display_name); + break; + case KIND_REBLOG: + icon = "media-playlist-repeat-symbolic"; + descr = _("%s boosted your status").printf (account.url, account.display_name); + break; + case KIND_REMOTE_REBLOG: + icon = "media-playlist-repeat-symbolic"; + descr = _("%s boosted").printf (account.url, account.display_name); + break; + case KIND_FAVOURITE: + icon = "starred-symbolic"; + descr = _("%s favorited your status").printf (account.url, account.display_name); + break; + case KIND_FOLLOW: + icon = "contact-new-symbolic"; + descr = _("%s now follows you").printf (account.url, account.display_name); + break; + case KIND_FOLLOW_REQUEST: + icon = "contact-new-symbolic"; + descr = _("%s wants to follow you").printf (account.url, account.display_name); + break; + case KIND_POLL: + icon = "emblem-default-symbolic"; + descr = _("Poll results"); + break; + default: + icon = null; + descr = null; + break; + } + } } diff --git a/src/Services/Accounts/Places.vala b/src/Services/Accounts/Places.vala new file mode 100644 index 0000000..18a1fea --- /dev/null +++ b/src/Services/Accounts/Places.vala @@ -0,0 +1,13 @@ +public class Tootle.Place : Object { + + public string title { get; set; } + public string icon { get; set; } + public int badge { get; set; default = 0; } + public bool separated { get; set; default = false; } + + [CCode (has_target = false)] + public delegate void OpenFunc (Dialogs.MainWindow window); + + public OpenFunc open_func { get; set; } + +} diff --git a/src/Views/Main.vala b/src/Views/Main.vala index f7b7a4b..96686eb 100644 --- a/src/Views/Main.vala +++ b/src/Views/Main.vala @@ -4,6 +4,7 @@ public class Tootle.Views.Main : Views.TabbedBase { public Main () { add_tab (new Views.Home ()); + add_tab (new Views.Notifications ()); add_tab (new Views.Local ()); add_tab (new Views.Federated ()); } diff --git a/src/Views/Sidebar.vala b/src/Views/Sidebar.vala index 1f3b4ea..d137abd 100644 --- a/src/Views/Sidebar.vala +++ b/src/Views/Sidebar.vala @@ -13,31 +13,46 @@ public class Tootle.Views.Sidebar : Box, AccountHolder { [GtkChild] unowned Label subtitle; protected InstanceAccount? account { get; set; default = null; } - GLib.ListStore item_model = new GLib.ListStore (typeof (Object)); - Item item_preferences = new Item () { - label = _("Preferences"), + protected GLib.ListStore app_items; + protected SliceListModel account_items; + protected FlattenListModel item_model; + + public static Place PREFERENCES = new Place () { + title = _("Preferences"), icon = "emblem-system-symbolic", - selectable = false, + //selectable = false, separated = true, - on_activated = () => { + open_func = () => { Dialogs.Preferences.open (); } }; - Item item_about = new Item () { - label = _("About"), + public static Place ABOUT = new Place () { + title = _("About"), icon = "help-about-symbolic", - selectable = false, - on_activated = () => { + //selectable = false, + open_func = () => { app.lookup_action ("about").activate (null); } }; construct { - construct_account_holder (); + app_items = new GLib.ListStore (typeof (Place)); + app_items.append (PREFERENCES); + app_items.append (ABOUT); + + account_items = new SliceListModel (null, 0, 15); + + var models = new GLib.ListStore (typeof (Object)); + models.append (account_items); + models.append (app_items); + item_model = new FlattenListModel (models); + items.bind_model (item_model, on_item_create); items.set_header_func (on_item_header_update); saved_accounts.set_header_func (on_account_header_update); + + construct_account_holder (); } protected virtual void on_accounts_changed (Gee.ArrayList accounts) { @@ -56,17 +71,13 @@ public class Tootle.Views.Sidebar : Box, AccountHolder { protected virtual void on_account_changed (InstanceAccount? account) { this.account = account; - - warning (account.handle); accounts_button.active = false; - item_model.remove_all (); if (account != null) { title.label = account.display_name; subtitle.label = account.handle; avatar.account = account; - - account.populate_user_menu (item_model); + account_items.model = account.known_places; } else { saved_accounts.unselect_all (); @@ -74,18 +85,8 @@ public class Tootle.Views.Sidebar : Box, AccountHolder { title.label = _("Anonymous"); subtitle.label = _("No account selected"); avatar.account = null; + account_items.model = null; } - - item_model.append (item_preferences); - item_model.append (item_about); - - // item_model.append (new Item () { - // label = "(Debug) Empty View", - // separated = true, - // on_activated = () => { - // app.main_window.open_view (new Views.ContentBase ()); - // } - // }); } [GtkCallback] void on_mode_changed () { @@ -100,44 +101,35 @@ public class Tootle.Views.Sidebar : Box, AccountHolder { // Item - public class Item : Object { - public VoidFunc? on_activated; - public string label { get; set; default = ""; } - public string icon { get; set; default = ""; } - public int badge { get; set; default = 0; } - public bool selectable { get; set; default = false; } - public bool separated { get; set; default = false; } - } - [GtkTemplate (ui = "/com/github/bleakgrey/tootle/ui/views/sidebar/item.ui")] protected class ItemRow : ListBoxRow { - public Item item; + public Place place; [GtkChild] unowned Image icon; [GtkChild] unowned Label label; [GtkChild] unowned Label badge; - public ItemRow (Item _item) { - item = _item; - item.bind_property ("label", label, "label", BindingFlags.SYNC_CREATE); - item.bind_property ("icon", icon, "icon-name", BindingFlags.SYNC_CREATE); - item.bind_property ("badge", badge, "label", BindingFlags.SYNC_CREATE); - item.bind_property ("badge", badge, "visible", BindingFlags.SYNC_CREATE, (b, src, ref target) => { + public ItemRow (Place place) { + this.place = place; + place.bind_property ("title", label, "label", BindingFlags.SYNC_CREATE); + place.bind_property ("icon", icon, "icon-name", BindingFlags.SYNC_CREATE); + place.bind_property ("badge", badge, "label", BindingFlags.SYNC_CREATE); + place.bind_property ("badge", badge, "visible", BindingFlags.SYNC_CREATE, (b, src, ref target) => { target.set_boolean (src.get_int () > 0); return true; }); - bind_property ("selectable", item, "selectable", BindingFlags.SYNC_CREATE); + // bind_property ("selectable", item, "selectable", BindingFlags.SYNC_CREATE); } } Widget on_item_create (Object obj) { - return new ItemRow (obj as Item); + return new ItemRow (obj as Place); } [GtkCallback] void on_item_activated (ListBoxRow _row) { var row = _row as ItemRow; - if (row.item.on_activated != null) - row.item.on_activated (); + if (row.place.open_func != null) + row.place.open_func (app.main_window); var flap = app.main_window.flap; if (flap.folded) @@ -150,7 +142,7 @@ public class Tootle.Views.Sidebar : Box, AccountHolder { row.set_header (null); - if (row.item.separated && before != null && !before.item.separated) { + if (row.place.separated && before != null && !before.place.separated) { row.set_header (new Separator (Orientation.HORIZONTAL)); } }