Display thread lines

This commit is contained in:
Bleak Grey 2020-10-24 13:54:37 +03:00 committed by GitHub
parent e28619a364
commit f1f8cd1fb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 175 additions and 74 deletions

View File

@ -40,3 +40,17 @@
padding: 0px;
margin: 0px;
}
.ttl-post {
padding: 0px;
}
.ttl-thread-line {
background: @theme_fg_color;
opacity: .1;
margin-top: -8px;
margin-bottom: -8px;
}
.ttl-large-body {
font-size: 110%;
}

View File

@ -54,8 +54,8 @@
<object class="HdyClamp" id="clamp">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="maximum_size">700</property>
<property name="tightening_threshold">700</property>
<property name="maximum_size">650</property>
<property name="tightening_threshold">650</property>
<child>
<object class="GtkBox" id="column_view">
<property name="visible">True</property>

View File

@ -417,9 +417,26 @@
</packing>
</child>
<child>
<placeholder/>
<object class="GtkImage" id="thread_line">
<property name="width_request">4</property>
<property name="height_request">32</property>
<property name="can_focus">False</property>
<property name="halign">center</property>
<property name="icon_size">0</property>
<style>
<class name="ttl-thread-line"/>
</style>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">0</property>
<property name="height">3</property>
</packing>
</child>
</object>
</child>
<style>
<class name="ttl-post"/>
</style>
</template>
</interface>

View File

@ -2,88 +2,105 @@ using Gtk;
public class Tootle.Views.Thread : Views.Base, IAccountListener {
public API.Status root_status { get; construct set; }
protected InstanceAccount? account = null;
protected Widgets.Status root_widget;
public API.Status root_status { get; construct set; }
protected InstanceAccount? account = null;
protected Widgets.Status root_widget;
public Thread (API.Status status) {
Object (
root_status: status,
status_message: STATUS_LOADING,
label: _("Conversation")
);
account_listener_init ();
}
public Thread (API.Status status) {
Object (
root_status: status,
status_message: STATUS_LOADING,
label: _("Conversation")
);
account_listener_init ();
}
public override void on_account_changed (InstanceAccount? acc) {
account = acc;
request ();
}
public override void on_account_changed (InstanceAccount? acc) {
account = acc;
request ();
}
Widgets.Status prepend (Entity entity, bool to_end = false){
var w = entity.to_widget () as Widgets.Status;
w.reveal_spoiler = true;
Widgets.Status append (Entity entity){
var w = entity.to_widget () as Widgets.Status;
w.reveal_spoiler = true;
content_list.insert (w, -1);
return w;
}
if (to_end)
content_list.insert (w, -1);
else
content_list.prepend (w);
void connect_threads () {
Widgets.Status? last_w = null;
string? last_id = null;
check_resize ();
return w;
}
Widget append (Entity entity) {
return prepend (entity, true);
}
content.get_children ().foreach (i => {
var w = i as Widgets.Status;
var id = w.status.formal.in_reply_to_id;
public void request () {
new Request.GET (@"/api/v1/statuses/$(root_status.id)/context")
.with_account (account)
.with_ctx (this)
.then ((sess, msg) => {
var root = network.parse (msg);
if (id == last_id) {
Widgets.Status.ThreadRole.connect_posts (last_w, w);
}
var ancestors = root.get_array_member ("ancestors");
ancestors.foreach_element ((array, i, node) => {
var status = Entity.from_json (typeof (API.Status), node);
append (status);
});
last_w = w;
last_id = w.status.formal.id;
});
root_widget = append (root_status) as Widgets.Status;
root_widget.expand_root ();
content.get_children ().foreach (i => {
var w = i as Widgets.Status;
w.install_thread_line ();
});
var descendants = root.get_array_member ("descendants");
descendants.foreach_element ((array, i, node) => {
var status = Entity.from_json (typeof (API.Status), node);
append (status);
});
root_widget.thread_line.hide ();
}
on_content_changed ();
public void request () {
new Request.GET (@"/api/v1/statuses/$(root_status.id)/context")
.with_account (account)
.with_ctx (this)
.then ((sess, msg) => {
int x,y;
translate_coordinates (root_widget, 0, header.get_allocated_height (), out x, out y);
scrolled.vadjustment.value = (double)(y*-1);
})
.exec ();
}
var root = network.parse (msg);
public static void open_from_link (string q) {
new Request.GET ("/api/v1/search")
.with_account ()
.with_param ("q", q)
.with_param ("resolve", "true")
.then ((sess, msg) => {
var root = network.parse (msg);
var statuses = root.get_array_member ("statuses");
var node = statuses.get_element (0);
if (node != null){
var status = API.Status.from (node);
window.open_view (new Views.Thread (status));
}
else
Desktop.open_uri (q);
})
.exec ();
}
var ancestors = root.get_array_member ("ancestors");
ancestors.foreach_element ((array, i, node) => {
var status = Entity.from_json (typeof (API.Status), node);
append (status);
});
root_widget = append (root_status) as Widgets.Status;
root_widget.expand_root ();
var descendants = root.get_array_member ("descendants");
descendants.foreach_element ((array, i, node) => {
var status = Entity.from_json (typeof (API.Status), node);
append (status);
});
connect_threads ();
on_content_changed ();
int x,y;
translate_coordinates (root_widget, 0, header.get_allocated_height (), out x, out y);
scrolled.vadjustment.value = (double)(y*-1);
})
.exec ();
}
public static void open_from_link (string q) {
new Request.GET ("/api/v1/search")
.with_account ()
.with_param ("q", q)
.with_param ("resolve", "true")
.then ((sess, msg) => {
var root = network.parse (msg);
var statuses = root.get_array_member ("statuses");
var node = statuses.get_element (0);
if (node != null){
var status = API.Status.from (node);
window.open_view (new Views.Thread (status));
}
else
Desktop.open_uri (q);
})
.exec ();
}
}

View File

@ -7,10 +7,38 @@ public class Tootle.Widgets.Status : ListBoxRow {
public API.Status status { get; construct set; }
public API.NotificationType? kind { get; construct set; }
public enum ThreadRole {
NONE,
START,
MIDDLE,
END;
public static void connect_posts (Widgets.Status? prev, Widgets.Status curr) {
if (prev == null) {
curr.thread_role = NONE;
return;
}
switch (prev.thread_role) {
case NONE:
prev.thread_role = START;
curr.thread_role = END;
break;
case END:
prev.thread_role = MIDDLE;
curr.thread_role = END;
break;
}
}
}
public ThreadRole thread_role { get; set; default = ThreadRole.NONE; }
[GtkChild] protected Grid grid;
[GtkChild] protected Image header_icon;
[GtkChild] protected Widgets.RichLabel header_label;
[GtkChild] public Image thread_line;
[GtkChild] public Widgets.Avatar avatar;
[GtkChild] protected Widgets.RichLabel name_label;
@ -234,6 +262,7 @@ public class Tootle.Widgets.Status : ListBoxRow {
public void expand_root () {
activatable = false;
content.selectable = true;
content.get_style_context ().add_class ("ttl-large-body");
var parent = content_column.get_parent () as Container;
var left_attach = parent.find_child_property ("left-attach");
@ -242,4 +271,28 @@ public class Tootle.Widgets.Status : ListBoxRow {
parent.set_child_property (content_column, 3, 2, width);
}
public void install_thread_line () {
var l = thread_line;
switch (thread_role) {
case NONE:
l.visible = false;
break;
case START:
l.valign = Align.FILL;
l.margin_top = 24;
l.visible = true;
break;
case MIDDLE:
l.valign = Align.FILL;
l.margin_top = 0;
l.visible = true;
break;
case END:
l.valign = Align.START;
l.margin_top = 0;
l.visible = true;
break;
}
}
}