feat: hashtags
- search results are now ActionRows and display information about usage - you can now (un)follow hashtags
This commit is contained in:
parent
17eb47ff4e
commit
9e3851858f
|
@ -77,6 +77,7 @@ sources = files(
|
|||
'src/API/SearchResults.vala',
|
||||
'src/API/Status.vala',
|
||||
'src/API/Tag.vala',
|
||||
'src/API/TagHistory.vala',
|
||||
'src/API/Poll.vala',
|
||||
'src/API/PollOption.vala',
|
||||
'src/Application.vala',
|
||||
|
|
|
@ -100,6 +100,9 @@ public class Tooth.Entity : GLib.Object, Widgetizable, Json.Serializable {
|
|||
case "hashtags":
|
||||
contains = typeof (API.Tag);
|
||||
break;
|
||||
case "history":
|
||||
contains = typeof (API.TagHistory);
|
||||
break;
|
||||
default:
|
||||
contains = typeof (Entity);
|
||||
break;
|
||||
|
|
|
@ -7,7 +7,6 @@ public class Tooth.API.Poll : GLib.Object, Json.Serializable{
|
|||
public bool expired { get; set; }
|
||||
public bool multiple { get; set; }
|
||||
public int64 votes_count { get; set; }
|
||||
public int64 voters_count { get; set; }
|
||||
public bool voted { get; set; default = true;}
|
||||
public ArrayList<int> own_votes { get; set; }
|
||||
public ArrayList<PollOption>? options{ get; set; default = null; }
|
||||
|
|
|
@ -4,17 +4,41 @@ public class Tooth.API.Tag : Entity, Widgetizable {
|
|||
|
||||
public string name { get; set; }
|
||||
public string url { get; set; }
|
||||
public Gee.ArrayList<API.TagHistory>? history { get; set; default = null; }
|
||||
public bool following { get; set; default = false; }
|
||||
|
||||
public static Tag from (Json.Node node) throws Error {
|
||||
return Entity.from_json (typeof (API.Tag), node) as API.Tag;
|
||||
}
|
||||
|
||||
public override void open () {
|
||||
}
|
||||
|
||||
public override Widget to_widget () {
|
||||
var encoded = Soup.URI.encode (name, null);
|
||||
var w = new Widgets.RichLabel (@"<a href=\"$(accounts.active.instance)/tags/$encoded\">#$name</a>");
|
||||
w.halign = Align.START;
|
||||
w.show ();
|
||||
var w = new Adw.ActionRow () {
|
||||
title = @"#$name",
|
||||
activatable = true
|
||||
};
|
||||
if (history != null && history.size > 0) {
|
||||
var last_history_entry = history.get(0);
|
||||
var total_uses = int.parse (last_history_entry.uses);
|
||||
var total_accounts = int.parse (last_history_entry.accounts);
|
||||
var suffix = _("yesterday");
|
||||
|
||||
if (history.size > 1) {
|
||||
last_history_entry = history.get(1);
|
||||
total_uses += int.parse (last_history_entry.uses);
|
||||
total_accounts += int.parse (last_history_entry.accounts);
|
||||
suffix = _("in the past 2 days");
|
||||
}
|
||||
|
||||
w.subtitle = _("Used %d times by %d people %s").printf (total_uses, total_accounts, suffix);
|
||||
}
|
||||
w.activated.connect(on_activated);
|
||||
return w;
|
||||
}
|
||||
|
||||
protected void on_activated () {
|
||||
app.main_window.open_view (new Views.Hashtag (name, following));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
public class Tooth.API.TagHistory : Entity {
|
||||
public string day { get; set; default = ""; }
|
||||
public string accounts { get; set; default = "0"; }
|
||||
public string uses { get; set; default = "0"; }
|
||||
}
|
|
@ -1,14 +1,81 @@
|
|||
public class Tooth.Views.Hashtag : Views.Timeline {
|
||||
|
||||
public Hashtag (string tag) {
|
||||
bool t_following = false;
|
||||
string t_tag = "";
|
||||
public Hashtag (string tag, bool? following = null) {
|
||||
Object (
|
||||
url: @"/api/v1/timelines/tag/$tag",
|
||||
label: "#"+tag
|
||||
url: @"/api/v1/timelines/tag/$tag",
|
||||
label: "#"+tag
|
||||
);
|
||||
|
||||
t_tag = tag;
|
||||
if (following != null) {
|
||||
t_following = following;
|
||||
create_follow_button();
|
||||
} else {
|
||||
init_tag();
|
||||
}
|
||||
}
|
||||
|
||||
Gtk.Button follow_tag_btn = new Gtk.Button.with_label(_("Follow"));
|
||||
private void create_follow_button() {
|
||||
if (t_following) {
|
||||
follow_tag_btn.label = _("Unfollow");
|
||||
follow_tag_btn.add_css_class("destructive-action");
|
||||
} else {
|
||||
follow_tag_btn.add_css_class("suggested-action");
|
||||
}
|
||||
follow_tag_btn.clicked.connect(follow);
|
||||
|
||||
header.pack_end(follow_tag_btn);
|
||||
}
|
||||
|
||||
private void update_button() {
|
||||
if (t_following) {
|
||||
follow_tag_btn.label = _("Follow");
|
||||
follow_tag_btn.remove_css_class("destructive-action");
|
||||
follow_tag_btn.add_css_class("suggested-action");
|
||||
} else {
|
||||
follow_tag_btn.label = _("Unfollow");
|
||||
follow_tag_btn.remove_css_class("suggested-action");
|
||||
follow_tag_btn.add_css_class("destructive-action");
|
||||
}
|
||||
t_following = !t_following;
|
||||
}
|
||||
|
||||
private void follow() {
|
||||
var action = "follow";
|
||||
if (t_following) {
|
||||
action = "unfollow";
|
||||
}
|
||||
update_button();
|
||||
|
||||
new Request.POST (@"/api/v1/tags/$t_tag/$action")
|
||||
.with_account (accounts.active)
|
||||
.then ((sess, msg) => {
|
||||
var root = network.parse (msg);
|
||||
if (!root.has_member("following")) {
|
||||
update_button();
|
||||
};
|
||||
})
|
||||
.exec ();
|
||||
}
|
||||
|
||||
private void init_tag() {
|
||||
new Request.GET (@"/api/v1/tags/$t_tag")
|
||||
.with_account (accounts.active)
|
||||
.then ((sess, msg) => {
|
||||
var node = network.parse_node (msg);
|
||||
var tag_info = API.Tag.from (node);
|
||||
t_following = tag_info.following;
|
||||
create_follow_button();
|
||||
})
|
||||
.exec ();
|
||||
}
|
||||
|
||||
public override string? get_stream_url () {
|
||||
var tag = url.substring (4);
|
||||
var split_url = url.split ("/");
|
||||
var tag = split_url[split_url.length - 1];
|
||||
return account != null ? @"$(account.instance)/api/v1/streaming/?stream=hashtag&tag=$tag&access_token=$(account.access_token)" : null;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,7 +88,7 @@ public class Tooth.Widgets.RichLabel : Adw.Bin {
|
|||
if ("/tags/" in url) {
|
||||
var encoded = url.split ("/tags/")[1];
|
||||
var tag = Soup.URI.decode (encoded);
|
||||
app.main_window.open_view (new Views.Hashtag (tag));
|
||||
app.main_window.open_view (new Views.Hashtag (tag, null));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ public class Tooth.Widgets.RichLabelContainer : Adw.Bin {
|
|||
if ("/tags/" in on_click_url) {
|
||||
var encoded = on_click_url.split ("/tags/")[1];
|
||||
var tag = Soup.URI.decode (encoded);
|
||||
app.main_window.open_view (new Views.Hashtag (tag));
|
||||
app.main_window.open_view (new Views.Hashtag (tag, null));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue