ssb: Hint at follow depth with profile image shape. Also, reload follow information the same way we re-determine channel unread status. Let's see if this feels good.

This commit is contained in:
Cory McWilliams 2025-01-11 13:48:06 -05:00
parent 6b0c49752c
commit 02759c6f83
10 changed files with 139 additions and 134 deletions

View File

@ -1,5 +1,5 @@
{
"type": "tildefriends-app",
"emoji": "🦀",
"previous": "&UOHm9X6pa1L0G0QdtiIqV/UW4vH/4rTA4i30IPqMzeQ=.sha256"
"previous": "&5YZ9ja1NymBZsDaHIrpgZCzn95R34Y1RQug6gy4EULU=.sha256"
}

View File

@ -38,8 +38,8 @@ class TfElement extends LitElement {
this.channels = [];
this.channels_unread = {};
this.channels_latest = {};
this.loading_channels_latest = 0;
this.loading_channels_latest_scheduled = 0;
this.loading_latest = 0;
this.loading_latest_scheduled = 0;
tfrpc.rpc.getBroadcasts().then((b) => {
self.broadcasts = b || [];
});
@ -147,7 +147,8 @@ class TfElement extends LitElement {
}
}
async fetch_about(ids, users) {
async fetch_about(following, users) {
let ids = Object.keys(following).sort();
const k_cache_version = 1;
let cache = await tfrpc.rpc.databaseGet('about');
let original_cache = cache;
@ -225,7 +226,11 @@ class TfElement extends LitElement {
}
users = users || {};
for (let id of Object.keys(cache.about)) {
users[id] = Object.assign(users[id] || {}, cache.about[id]);
users[id] = Object.assign(
{follow_depth: following[id]?.d},
users[id] || {},
cache.about[id]
);
}
return Object.assign({}, users);
}
@ -248,7 +253,7 @@ class TfElement extends LitElement {
this.load_channels();
}
}
this.schedule_load_channels_latest();
this.schedule_load_latest();
}
async _handle_whoami_changed(event) {
@ -307,7 +312,6 @@ class TfElement extends LitElement {
ranges.push([i, Math.min(i + k_chunk_size, latest), true]);
}
}
console.log(cache);
for (let range of ranges) {
let messages = await tfrpc.rpc.query(
`
@ -340,13 +344,10 @@ class TfElement extends LitElement {
JSON.stringify(cache)
);
}
console.log(cache);
return cache.latest;
}
async load_channels_latest(following) {
this.loading_channels_latest++;
try {
let start_time = new Date();
let latest_private = this.get_latest_private(following);
let channels = await tfrpc.rpc.query(
@ -392,27 +393,26 @@ class TfElement extends LitElement {
});
console.log('private took', (new Date() - start_time) / 1000.0);
});
} finally {
this.loading_channels_latest--;
}
}
_schedule_load_channels_latest_timer() {
--this.loading_channels_latest_scheduled;
this.schedule_load_channels_latest();
_schedule_load_latest_timer() {
--this.loading_latest_scheduled;
this.schedule_load_latest();
}
schedule_load_channels_latest() {
if (!this.loading_channels_latest) {
schedule_load_latest() {
if (!this.loading_latest) {
this.shadowRoot.getElementById('tf-tab-news')?.load_latest();
this.load_channels_latest(this.following);
} else if (!this.loading_channels_latest_scheduled) {
this.loading_channels_latest_scheduled++;
setTimeout(this._schedule_load_channels_latest_timer.bind(this), 5000);
this.load();
} else if (!this.loading_latest_scheduled) {
this.loading_latest_scheduled++;
setTimeout(this._schedule_load_latest_timer.bind(this), 5000);
}
}
async load() {
this.loading_latest = true;
try {
let start_time = new Date();
let whoami = this.whoami;
let following = await tfrpc.rpc.following([whoami], 2);
@ -431,7 +431,8 @@ class TfElement extends LitElement {
this.channels_unread = JSON.parse(
(await tfrpc.rpc.databaseGet('unread')) ?? '{}'
);
users = await this.fetch_about(Object.keys(following).sort(), users);
this.following = Object.keys(following);
users = await this.fetch_about(following, users);
console.log(
'about took',
(new Date() - start_time) / 1000.0,
@ -439,13 +440,15 @@ class TfElement extends LitElement {
Object.keys(users).length,
'users'
);
this.following = Object.keys(following);
this.users = users;
console.log(
`load finished ${whoami} => ${this.whoami} in ${(new Date() - start_time) / 1000}`
);
this.whoami = whoami;
this.loaded = whoami;
} finally {
this.loading_latest = false;
}
}
channel_set_unread(event) {

View File

@ -589,9 +589,7 @@ class TfMessageElement extends LitElement {
let image;
let description;
if (content.name !== undefined) {
name = html`<div>
<b>Name:</b> ${content.name}
</div>`;
name = html`<div><b>Name:</b> ${content.name}</div>`;
}
if (content.image !== undefined) {
image = html`
@ -600,18 +598,14 @@ class TfMessageElement extends LitElement {
}
if (content.description !== undefined) {
description = html`
<div
style="flex: 1 0 50%; overflow-wrap: anywhere"
>
<div style="flex: 1 0 50%; overflow-wrap: anywhere">
<div>${unsafeHTML(tfutils.markdown(content.description))}</div>
</div>
`;
}
let update =
content.about == this.message.author
? html`<div style="font-weight: bold">
Updated profile.
</div>`
? html`<div style="font-weight: bold">Updated profile.</div>`
: html`<div style="font-weight: bold">
Updated profile for
<tf-user id=${content.about} .users=${this.users}></tf-user>.

View File

@ -142,7 +142,8 @@ class TfTabConnectionsElement extends LitElement {
}, {})
);
return html`
${connection.connected ? html`
${connection.connected
? html`
<button
class="w3-button w3-theme-d1"
@click=${() => tfrpc.rpc.closeConnection(connection.id)}
@ -270,16 +271,19 @@ class TfTabConnectionsElement extends LitElement {
<div class="w3-container">
${this.identities.map(
(x) =>
html`<div class="w3-tag w3-round w3-theme-l3" style="padding: 4px; margin: 2px; max-width: 100%; text-wrap: nowrap; overflow: hidden">
html`<div
class="w3-tag w3-round w3-theme-l3"
style="padding: 4px; margin: 2px; max-width: 100%; text-wrap: nowrap; overflow: hidden"
>
${x == this.server_identity
? html`<div class="w3-tag w3-medium w3-round w3-theme-l1"
>🖥 local server</div
>`
? html`<div class="w3-tag w3-medium w3-round w3-theme-l1">
🖥 local server
</div>`
: undefined}
${this.my_identities.indexOf(x) != -1
? html`<div class="w3-tag w3-medium w3-round w3-theme-d1"
>😎 you</div
>`
? html`<div class="w3-tag w3-medium w3-round w3-theme-d1">
😎 you
</div>`
: undefined}
<tf-user id=${x} .users=${this.users}></tf-user>
</div>`

View File

@ -19,8 +19,10 @@ class TfUserElement extends LitElement {
}
render() {
let user = this.users[this.id];
let shape = user && user.follow_depth >= 2 ? 'w3-circle' : 'w3-round';
let image = html`<span
class="w3-theme-light w3-circle"
class=${'w3-theme-l4 ' + shape}
style="display: inline-block; width: 2em; height: 2em; text-align: center; line-height: 2em"
>?</span
>`;
@ -29,13 +31,13 @@ class TfUserElement extends LitElement {
>${name !== undefined ? name : this.id}</a
>`;
if (this.users[this.id]) {
let image_link = this.users[this.id].image;
if (user) {
let image_link = user.image;
image_link =
typeof image_link == 'string' ? image_link : image_link?.link;
if (image_link !== undefined) {
image = html`<img
class="w3-circle"
class=${'w3-theme-l4 ' + shape}
style="width: 2em; height: 2em; vertical-align: middle; object-fit: cover"
src="/${image_link}/view"
/>`;

View File

@ -1356,8 +1356,7 @@ bool tf_ssb_connection_is_client(tf_ssb_connection_t* connection)
bool tf_ssb_connection_is_connected(tf_ssb_connection_t* connection)
{
return (connection->state == k_tf_ssb_state_verified || connection->state == k_tf_ssb_state_server_verified) &&
!connection->is_closing;
return (connection->state == k_tf_ssb_state_verified || connection->state == k_tf_ssb_state_server_verified) && !connection->is_closing;
}
bool tf_ssb_connection_is_closing(tf_ssb_connection_t* connection)

View File

@ -1455,6 +1455,7 @@ tf_ssb_following_t* tf_ssb_db_following_deep(tf_ssb_t* ssb, const char** ids, in
result[write_index].blocking_count = following[i]->blocking_count;
result[write_index].followed_by_count = following[i]->ref_count;
result[write_index].blocked_by_count = following[i]->block_ref_count;
result[write_index].depth = following[i]->depth;
write_index++;
}
}

View File

@ -286,6 +286,8 @@ typedef struct _tf_ssb_following_t
int followed_by_count;
/** The number of known users blocking the account. */
int blocked_by_count;
/** Degree of separation between initial accounts and this account. */
int depth;
/** The account's identity. */
char id[k_id_base64_len];
} tf_ssb_following_t;

View File

@ -2187,6 +2187,7 @@ static void _tf_ssb_following_after_work(tf_ssb_t* ssb, int status, void* user_d
JS_SetPropertyStr(context, entry, "ob", JS_NewInt32(context, following->out_following[i].blocking_count));
JS_SetPropertyStr(context, entry, "if", JS_NewInt32(context, following->out_following[i].followed_by_count));
JS_SetPropertyStr(context, entry, "ib", JS_NewInt32(context, following->out_following[i].blocked_by_count));
JS_SetPropertyStr(context, entry, "d", JS_NewInt32(context, following->out_following[i].depth));
JS_SetPropertyStr(context, object, following->out_following[i].id, entry);
}
JSValue result = JS_Call(context, following->promise[0], JS_UNDEFINED, 1, &object);

View File

@ -446,8 +446,7 @@ static void _tf_ssb_rpc_send_endpoints(tf_ssb_t* ssb)
for (int i = 0; i < count; i++)
{
char id[k_id_base64_len] = { 0 };
if ((tf_ssb_connection_is_attendant(connections[i]) || tf_ssb_connection_is_endpoint(connections[i])) &&
tf_ssb_connection_is_connected(connections[i]) &&
if ((tf_ssb_connection_is_attendant(connections[i]) || tf_ssb_connection_is_endpoint(connections[i])) && tf_ssb_connection_is_connected(connections[i]) &&
tf_ssb_connection_get_id(connections[i], id, sizeof(id)))
{
JS_SetPropertyUint32(context, endpoints, id_count++, JS_NewString(context, id));