From d3d3596210ff1cda695dfe362eb78170fe36f472 Mon Sep 17 00:00:00 2001 From: GeopJr Date: Wed, 1 Feb 2023 17:07:12 +0200 Subject: [PATCH] feat: instance info (#63) * chore: status_reactions => compat_status_reactions let's prefix all instance compatibility properties with compat_ * feat: deserialize ArrayLists of string * feat: instance info * fix(SecretAccountStore): set instance_info as null --- meson.build | 6 +++ src/API/Entity.vala | 15 ++++++ src/API/Instance.vala | 51 +++++++++++++++++++ src/API/Instance/Mastodon/Configuration.vala | 6 +++ .../Configuration/MediaAttachments.vala | 8 +++ .../Mastodon/Configuration/Polls.vala | 13 +++++ .../Mastodon/Configuration/Reactions.vala | 3 ++ .../Mastodon/Configuration/Statuses.vala | 5 ++ src/API/Status.vala | 2 +- src/Services/Accounts/InstanceAccount.vala | 15 +++++- src/Services/Accounts/SecretAccountStore.vala | 1 + src/Widgets/Status.vala | 4 +- 12 files changed, 125 insertions(+), 4 deletions(-) create mode 100644 src/API/Instance.vala create mode 100644 src/API/Instance/Mastodon/Configuration.vala create mode 100644 src/API/Instance/Mastodon/Configuration/MediaAttachments.vala create mode 100644 src/API/Instance/Mastodon/Configuration/Polls.vala create mode 100644 src/API/Instance/Mastodon/Configuration/Reactions.vala create mode 100644 src/API/Instance/Mastodon/Configuration/Statuses.vala diff --git a/meson.build b/meson.build index 844dc4a..7b389c8 100644 --- a/meson.build +++ b/meson.build @@ -63,6 +63,12 @@ sources = files( 'src/API/Emoji.vala', 'src/API/EmojiReaction.vala', 'src/API/Entity.vala', + 'src/API/Instance.vala', + 'src/API/Instance/Mastodon/Configuration.vala', + 'src/API/Instance/Mastodon/Configuration/MediaAttachments.vala', + 'src/API/Instance/Mastodon/Configuration/Polls.vala', + 'src/API/Instance/Mastodon/Configuration/Reactions.vala', + 'src/API/Instance/Mastodon/Configuration/Statuses.vala', 'src/API/List.vala', 'src/API/Mention.vala', 'src/API/Notification.vala', diff --git a/src/API/Entity.vala b/src/API/Entity.vala index 87ed671..0adc743 100644 --- a/src/API/Entity.vala +++ b/src/API/Entity.vala @@ -72,6 +72,9 @@ public class Tooth.Entity : GLib.Object, Widgetizable, Json.Serializable { //There has to be a better way switch (prop) { + case "supported-mime-types": + case "languages": + return des_list_string(out val, node); case "media-attachments": contains = typeof (API.Attachment); break; @@ -123,6 +126,18 @@ public class Tooth.Entity : GLib.Object, Widgetizable, Json.Serializable { return true; } + public static bool des_list_string (out Value val, Json.Node node) { + var arr = new Gee.ArrayList (); + if (!node.is_null ()) { + node.get_array ().foreach_element ((array, i, elem) => { + var obj = (string) elem.get_string(); + arr.add (obj); + }); + } + val = arr; + return true; + } + public override Json.Node serialize_property (string prop, Value val, ParamSpec spec) { var type = spec.value_type; // debug (@"serializing $prop of type $(val.type_name ())"); diff --git a/src/API/Instance.vala b/src/API/Instance.vala new file mode 100644 index 0000000..02fb828 --- /dev/null +++ b/src/API/Instance.vala @@ -0,0 +1,51 @@ +public class Tooth.API.Instance : Entity { + public Gee.ArrayList? languages { get; set; } + public API.Mastodon.Configurations? configuration { get; set; default = null; } + public int64 max_toot_chars { get; set; default = 0; } + public API.Mastodon.Configuration.Polls? poll_limits { get; set; default = null; } + public int64 upload_limit { get; set; default = 0; } + + public int64 compat_status_max_characters { + get { + if (configuration != null) { + return configuration.statuses.max_characters; + } + + return max_toot_chars; + } + } + + public int64 compat_status_max_image_size { + get { + if (configuration != null) { + return configuration.media_attachments.image_size_limit; + } + + return upload_limit; + } + } + + public int64 compat_status_max_video_size { + get { + if (configuration != null) { + return configuration.media_attachments.video_size_limit; + } + + return upload_limit; + } + } + + public API.Mastodon.Configuration.Polls? compat_status_polls { + get { + if (configuration != null) { + return configuration.polls; + } + + return poll_limits; + } + } + + public static API.Instance from (Json.Node node) throws Error { + return Entity.from_json (typeof (API.Instance), node) as API.Instance; + } +} diff --git a/src/API/Instance/Mastodon/Configuration.vala b/src/API/Instance/Mastodon/Configuration.vala new file mode 100644 index 0000000..95b5ab5 --- /dev/null +++ b/src/API/Instance/Mastodon/Configuration.vala @@ -0,0 +1,6 @@ +public class Tooth.API.Mastodon.Configurations : Entity { + public API.Mastodon.Configuration.Statuses statuses { get; set; } + public API.Mastodon.Configuration.MediaAttachments media_attachments { get; set; } + public API.Mastodon.Configuration.Polls polls { get; set; } + public API.Mastodon.Configuration.Reactions? reactions { get; set; default = null; } +} diff --git a/src/API/Instance/Mastodon/Configuration/MediaAttachments.vala b/src/API/Instance/Mastodon/Configuration/MediaAttachments.vala new file mode 100644 index 0000000..a3e243a --- /dev/null +++ b/src/API/Instance/Mastodon/Configuration/MediaAttachments.vala @@ -0,0 +1,8 @@ +public class Tooth.API.Mastodon.Configuration.MediaAttachments : Entity { + public Gee.ArrayList supported_mime_types { get; set; } + public int64 image_size_limit { get; set; } + public int64 image_matrix_limit { get; set; } + public int64 video_size_limit { get; set; } + public int64 video_frame_rate_limit { get; set; } + public int64 video_matrix_limit { get; set; } +} diff --git a/src/API/Instance/Mastodon/Configuration/Polls.vala b/src/API/Instance/Mastodon/Configuration/Polls.vala new file mode 100644 index 0000000..23d9a54 --- /dev/null +++ b/src/API/Instance/Mastodon/Configuration/Polls.vala @@ -0,0 +1,13 @@ +public class Tooth.API.Mastodon.Configuration.Polls : Entity { + public int64 max_options { get; set; } + public int64 max_characters_per_option { get; set; default = -1; } + public int64 max_option_chars { get; set; default = -1; } + public int64 min_expiration { get; set; } + public int64 max_expiration { get; set; } + + public int64 compat_status_poll_max_characters { + get { + return max_characters_per_option != -1 ? max_characters_per_option : max_option_chars; + } + } +} diff --git a/src/API/Instance/Mastodon/Configuration/Reactions.vala b/src/API/Instance/Mastodon/Configuration/Reactions.vala new file mode 100644 index 0000000..ba98f72 --- /dev/null +++ b/src/API/Instance/Mastodon/Configuration/Reactions.vala @@ -0,0 +1,3 @@ +public class Tooth.API.Mastodon.Configuration.Reactions : Entity { + public int64 max_reactions { get; set; } +} diff --git a/src/API/Instance/Mastodon/Configuration/Statuses.vala b/src/API/Instance/Mastodon/Configuration/Statuses.vala new file mode 100644 index 0000000..41768ab --- /dev/null +++ b/src/API/Instance/Mastodon/Configuration/Statuses.vala @@ -0,0 +1,5 @@ +public class Tooth.API.Mastodon.Configuration.Statuses : Entity { + public int64 max_characters { get; set; } + public int64 max_media_attachments { get; set; } + public int64 characters_reserved_per_url { get; set; default = 0; } +} diff --git a/src/API/Status.vala b/src/API/Status.vala index 27aaf47..898a7dc 100644 --- a/src/API/Status.vala +++ b/src/API/Status.vala @@ -33,7 +33,7 @@ public class Tooth.API.Status : Entity, Widgetizable { public ArrayList? media_attachments { get; set; default = null; } public API.Poll? poll { get; set; default = null; } - public ArrayList? status_reactions { + public ArrayList? compat_status_reactions { get { if (emoji_reactions != null) { return emoji_reactions; diff --git a/src/Services/Accounts/InstanceAccount.vala b/src/Services/Accounts/InstanceAccount.vala index dfcbad3..0644a87 100644 --- a/src/Services/Accounts/InstanceAccount.vala +++ b/src/Services/Accounts/InstanceAccount.vala @@ -16,6 +16,7 @@ public class Tooth.InstanceAccount : API.Account, Streamable { public const string KIND_REMOTE_REBLOG = "__remote-reblog"; public string? backend { set; get; } + public API.Instance? instance_info { get; set; } public string? instance { get; set; } public string? client_id { get; set; } public string? client_secret { get; set; } @@ -42,7 +43,9 @@ public class Tooth.InstanceAccount : API.Account, Streamable { } } - public virtual signal void activated () {} + public virtual signal void activated () { + gather_instance_info (); + } public virtual signal void deactivated () {} public virtual signal void added () { subscribed = true; @@ -179,6 +182,16 @@ public class Tooth.InstanceAccount : API.Account, Streamable { public ArrayList notification_inhibitors { get; set; default = new ArrayList (); } private bool passed_init_notifications = false; + public void gather_instance_info () { + new Request.GET ("/api/v1/instance") + .with_account (this) + .then ((sess, msg) => { + var node = network.parse_node (msg); + instance_info = API.Instance.from (node); + }) + .exec (); + } + public void init_notifications () { if (passed_init_notifications) return; diff --git a/src/Services/Accounts/SecretAccountStore.vala b/src/Services/Accounts/SecretAccountStore.vala index b0ccb4d..538c0c5 100644 --- a/src/Services/Accounts/SecretAccountStore.vala +++ b/src/Services/Accounts/SecretAccountStore.vala @@ -73,6 +73,7 @@ public class Tooth.SecretAccountStore : AccountStore { attrs["version"] = VERSION; var generator = new Json.Generator (); + account.instance_info = null; generator.set_root (account.to_json ()); var secret = generator.to_data (null); var label = _("%s Account").printf (account.backend); diff --git a/src/Widgets/Status.vala b/src/Widgets/Status.vala index 6b6401b..2890005 100644 --- a/src/Widgets/Status.vala +++ b/src/Widgets/Status.vala @@ -85,7 +85,7 @@ public class Tooth.Widgets.Status : ListBoxRow { public bool is_conversation_open { get; set; default = false; } public Gee.ArrayList? reactions { - get { return status.formal.status_reactions; } + get { return status.formal.compat_status_reactions; } set { if (value == null) return; @@ -298,7 +298,7 @@ public class Tooth.Widgets.Status : ListBoxRow { return true; }); formal_bindings.bind_property ("account", avatar, "account", BindingFlags.SYNC_CREATE); - formal_bindings.bind_property ("status-reactions", this, "reactions", BindingFlags.SYNC_CREATE); + formal_bindings.bind_property ("compat-status-reactions", this, "reactions", BindingFlags.SYNC_CREATE); formal_bindings.bind_property ("has-spoiler", this, "reveal-spoiler", BindingFlags.SYNC_CREATE, (b, src, ref target) => { target.set_boolean (!src.get_boolean () || settings.show_spoilers); return true;