diff --git a/apps/cory/ssblit.json b/apps/cory/ssblit.json
index 8d218e10..3f800199 100644
--- a/apps/cory/ssblit.json
+++ b/apps/cory/ssblit.json
@@ -1 +1 @@
-{"type":"tildefriends-app","files":{"app.js":"&b8IFBOMDtcvY5XNtUQIUeoE+++/TO8LDp86xNFIaux8=.sha256","lit-all.min.js":"&N4A12AsifdQgwdpII0SFtG513BfoLpmPjdJ9VTDftpg=.sha256","index.html":"&WH8A5tF25xlfPDGei2TCQc2/HJFJf5DuRN1GRSYQhhk=.sha256","script.js":"&diQfpbxjgd/jSPnIoAoWT75B8Pll1I5JYXhu+/phj9k=.sha256","lit-all.min.js.map":"&oFY9wO4MnujgfGNGv4VggHc5V5JwX4C8csqKZ6KJYbE=.sha256","tf-id-picker.js":"&ewIlLZNhaHm2dztxqj2Ft38WZkNPQxYfOGBrwTDUhds=.sha256","tf-app.js":"&Ss7Cw1jQkpqk5ckTTndYFtIMrEQRDK9vmMWi2nALCt0=.sha256","tf-message.js":"&KE1fWTqPMZR0yIRXPBGy8u1chR6LTguSK6swo+lFgE4=.sha256","tf-user.js":"&L6+7BnBq+UOoTMO6o8+u5JFTl0UBtCPDw8bb8ppDrkA=.sha256","tf-utils.js":"&N2yKZwFnb2GbPeipgQtu6xFvezENNOgud9G7EhCQ/K0=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&oo0iWvT+c2rU91zWpBIfPePRzmU8qmSnVOm+QCQqG/I=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&htPMi2z6Bmgi3f9jCnECCDZRCHACnDRjOl1kgPm+W80=.sha256","tf-styles.js":"&BkvFkMpGyL0DYP6FISFKR4pe6ZBOp8t6tQEzWZ4IQYs=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-connections.js":"&YUD4n/r95AwD2fA63HHE2eQt4E/27gF+4/MYrdvoasw=.sha256"}}
\ No newline at end of file
+{"type":"tildefriends-app","files":{"app.js":"&viCT+Sz8weP/j5V47w0wA4sk46HM4uy6lajX5NtoqHE=.sha256","lit-all.min.js":"&N4A12AsifdQgwdpII0SFtG513BfoLpmPjdJ9VTDftpg=.sha256","index.html":"&WH8A5tF25xlfPDGei2TCQc2/HJFJf5DuRN1GRSYQhhk=.sha256","script.js":"&G8puK9Q4MngHy3D4ppcKyT49WKbHD2OCeUcAw2ghTDE=.sha256","lit-all.min.js.map":"&oFY9wO4MnujgfGNGv4VggHc5V5JwX4C8csqKZ6KJYbE=.sha256","tf-id-picker.js":"&pg1gLK150HFai73TcmAe5E/dMpMqmbhyre/+/J4XmHo=.sha256","tf-app.js":"&Zt1x1urnzk0D9TxQvgJqOjdHelW+bei7CRupODgvAsk=.sha256","tf-message.js":"&KE1fWTqPMZR0yIRXPBGy8u1chR6LTguSK6swo+lFgE4=.sha256","tf-user.js":"&L6+7BnBq+UOoTMO6o8+u5JFTl0UBtCPDw8bb8ppDrkA=.sha256","tf-utils.js":"&N2yKZwFnb2GbPeipgQtu6xFvezENNOgud9G7EhCQ/K0=.sha256","commonmark.min.js":"&bfBaMLU19d1p/vPBF9hlARqDX002KXG/UOfxOahZhe4=.sha256","tf-compose.js":"&oo0iWvT+c2rU91zWpBIfPePRzmU8qmSnVOm+QCQqG/I=.sha256","emojis.json":"&h3P4pez+AI4aYdsN0dJ3pbUEFR0276t9AM20caj/W/s=.sha256","emojis.js":"&htPMi2z6Bmgi3f9jCnECCDZRCHACnDRjOl1kgPm+W80=.sha256","tf-styles.js":"&BkvFkMpGyL0DYP6FISFKR4pe6ZBOp8t6tQEzWZ4IQYs=.sha256","tf-profile.js":"&vRKjsnYvOiHCQahzEfznCvP5YDwUPtltlpWf+pxwZ1Y=.sha256","commonmark-linkify.js":"&X+hNNkmSRvKY86khyAun+cXksquXbMakZdINbGbx30g=.sha256","tf-tab-search.js":"&Q4bstnLzTPmCKJP+cf7FfRZJVuGAltEely4oIovUVaI=.sha256","tf-tab-news.js":"&Pc/FkHOPRPyWZi/znjquVtXeykzqqFygVuNm0dxrwlI=.sha256","tf-tab-connections.js":"&jSnF/5NmgqxRze1XQAEGOW5mPzOV1/8aCyrDRZu34IQ=.sha256","tf-news.js":"&C1dKe98kQOkClnAbGvcreC15IdlTrD9J4RFohspnsSE=.sha256"}}
\ No newline at end of file
diff --git a/apps/cory/ssblit/app.js b/apps/cory/ssblit/app.js
index c06d8d28..9f4ec03f 100644
--- a/apps/cory/ssblit/app.js
+++ b/apps/cory/ssblit/app.js
@@ -15,6 +15,9 @@ tfrpc.register(async function databaseGet(key) {
tfrpc.register(async function databaseSet(key, value) {
return g_database ? g_database.set(key, value) : undefined;
});
+tfrpc.register(async function createIdentity() {
+ return ssb.createIdentity();
+});
tfrpc.register(async function getIdentities() {
return ssb.getIdentities();
});
diff --git a/apps/cory/ssblit/script.js b/apps/cory/ssblit/script.js
index 7c16e66f..7730bce9 100644
--- a/apps/cory/ssblit/script.js
+++ b/apps/cory/ssblit/script.js
@@ -6,5 +6,8 @@ import * as tf_app from './tf-app.js';
import * as tf_message from './tf-message.js';
import * as tf_user from './tf-user.js';
import * as tf_compose from './tf-compose.js';
+import * as tf_news from './tf-news.js';
import * as tf_profile from './tf-profile.js';
-import * as tf_connections from './tf-connections.js';
+import * as tf_tab_news from './tf-tab-news.js';
+import * as tf_tab_search from './tf-tab-search.js';
+import * as tf_tab_connections from './tf-tab-connections.js';
diff --git a/apps/cory/ssblit/tf-app.js b/apps/cory/ssblit/tf-app.js
index 57407327..a3b2e7c8 100644
--- a/apps/cory/ssblit/tf-app.js
+++ b/apps/cory/ssblit/tf-app.js
@@ -1,4 +1,4 @@
-import {LitElement, html, css} from './lit-all.min.js';
+import {LitElement, html, css, guard, until} from './lit-all.min.js';
import * as tfrpc from '/static/tfrpc.js';
import {styles} from './tf-styles.js';
@@ -6,11 +6,6 @@ class TfElement extends LitElement {
static get properties() {
return {
whoami: {type: String},
- ids: {type: Array},
- messages: {type: Array},
- users: {type: Object},
- allFollowing: {type: Array},
- status: {type: Array},
hash: {type: String},
unread: {type: Array},
tab: {type: String},
@@ -24,25 +19,16 @@ class TfElement extends LitElement {
constructor() {
super();
let self = this;
- this.ids = [];
- this.users = {};
- this.messages = [];
- this.allFollowing = [];
- this.status = [];
- this.messages_by_id = {};
this.hash = '#';
- this.loading = false;
this.unread = [];
this.tab = 'news';
this.broadcasts = [];
this.connections = [];
- tfrpc.rpc.getIdentities().then(ids => { self.ids = ids || [] });
tfrpc.rpc.getBroadcasts().then(b => { self.broadcasts = b || [] });
tfrpc.rpc.getConnections().then(c => { self.connections = c || [] });
tfrpc.rpc.getHash().then(hash => self.hash = hash || '#');
tfrpc.register(function hashChanged(hash) {
self.hash = hash;
- self.load();
});
tfrpc.register(async function notifyNewMessage(id) {
await self.fetch_new_message(id);
@@ -54,6 +40,9 @@ class TfElement extends LitElement {
self.connections = value;
}
});
+ tfrpc.rpc.localStorageGet('whoami').then(function(value) {
+ self.whoami = value;
+ });
}
async contacts_internal(id, last_row_id, following, max_row_id) {
@@ -85,27 +74,21 @@ class TfElement extends LitElement {
return result;
}
- async contact(id, last_row_id, following, max_row_id) {
- if (this.users[id]?.following) {
- return this.users[id];
- }
-
+ async contact(id, last_row_id, following, max_row_id, contact_cache) {
let result = await this.contacts_internal(id, last_row_id, following, max_row_id);
- let users = this.users;
- users[id] = Object.assign(users[id] || {}, result);
- following[id] = users[id];
- this.users = users;
+ contact_cache[id] = Object.assign(contact_cache[id] || {}, result);
+ following[id] = contact_cache[id];
return result;
}
- async following_deep_internal(ids, depth, blocking, last_row_id, following, max_row_id) {
- let contacts = await Promise.all([...new Set(ids)].map(x => this.contact(x, last_row_id, following, max_row_id)));
+ async following_deep_internal(ids, depth, blocking, last_row_id, following, max_row_id, contact_cache) {
+ let contacts = await Promise.all([...new Set(ids)].map(x => this.contact(x, last_row_id, following, max_row_id, contact_cache)));
let result = {};
for (let i = 0; i < ids.length; i++) {
let id = ids[i];
let contact = contacts[i];
let found = Object.keys(contact.following).filter(y => !contact.blocking[y]);
- let deeper = depth > 1 ? await this.following_deep_internal(found, depth - 1, Object.assign({}, contact.blocking, blocking), last_row_id, following, max_row_id) : [];
+ let deeper = depth > 1 ? await this.following_deep_internal(found, depth - 1, Object.assign({}, contact.blocking, blocking), last_row_id, following, max_row_id, contact_cache) : [];
result[id] = [id, ...found, ...deeper];
}
return [...new Set(Object.values(result).flat())];
@@ -122,16 +105,17 @@ class TfElement extends LitElement {
last_row_id: 0,
};
}
+ let contact_cache = {};
let max_row_id = (await tfrpc.rpc.query(`
SELECT MAX(rowid) AS max_row_id FROM messages
`, []))[0].max_row_id;
- let result = await this.following_deep_internal(ids, depth, blocking, cache.last_row_id, cache.following, max_row_id);
+ let result = await this.following_deep_internal(ids, depth, blocking, cache.last_row_id, cache.following, max_row_id, contact_cache);
cache.last_row_id = max_row_id;
await tfrpc.rpc.databaseSet('following', JSON.stringify(cache));
return result;
}
- async fetch_about(ids) {
+ async fetch_about(ids, users) {
const k_cache_version = 1;
let cache = await tfrpc.rpc.databaseGet('about');
cache = cache ? JSON.parse(cache) : {};
@@ -191,50 +175,11 @@ class TfElement extends LitElement {
}
cache.last_row_id = max_row_id;
await tfrpc.rpc.databaseSet('about', JSON.stringify(cache));
- let users = this.users || {};
+ users = users || {};
for (let id of Object.keys(cache.about)) {
users[id] = Object.assign(users[id] || {}, cache.about[id]);
}
- this.users = Object.assign({}, users);
- }
-
- async fetch_messages() {
- if (this.hash.startsWith('#@')) {
- return await tfrpc.rpc.query(
- `
- SELECT messages.*
- FROM messages
- WHERE messages.author = ?
- ORDER BY sequence DESC
- LIMIT 20
- `,
- [
- this.hash.substring(1),
- ]);
- } else if (this.hash.startsWith('#%')) {
- return await tfrpc.rpc.query(
- `
- SELECT messages.*
- FROM messages
- WHERE id = ?
- `,
- [
- this.hash.substring(1),
- ]);
- } else {
- return await tfrpc.rpc.query(
- `
- SELECT messages.*
- FROM messages
- JOIN json_each(?) AS following ON messages.author = following.value
- WHERE messages.timestamp > ?
- ORDER BY messages.timestamp DESC
- `,
- [
- JSON.stringify(this.allFollowing),
- new Date().valueOf() - 24 * 60 * 60 * 1000,
- ]);
- }
+ return Object.assign({}, users);
}
async fetch_new_message(id) {
@@ -261,199 +206,51 @@ class TfElement extends LitElement {
}
}
- async show_more() {
- let unread = this.unread;
- this.unread = [];
- this.process_messages(unread);
- await this.finalize_messages();
- }
-
- record_status(text) {
- let now = new Date();
- if (this.status.length) {
- this.status[this.status.length - 1].end_time = now;
- console.log(
- this.status[this.status.length - 1].text,
- (now - this.status[this.status.length - 1].start_time).valueOf());
- }
- this.status.push({
- text: text,
- start_time: now,
- });
- }
-
- ensure_message(id) {
- let found = this.messages_by_id[id];
- if (found) {
- return found;
- } else {
- let added = {
- id: id,
- placeholder: true,
- content: '"placeholder"',
- parent_message: undefined,
- child_messages: [],
- votes: [],
- };
- this.messages_by_id[id] = added;
- return added;
- }
- }
-
- process_messages(messages) {
- let self = this;
-
- function link_message(message) {
- if (message.content.type === 'vote') {
- let parent = self.ensure_message(message.content.vote.link);
- if (!parent.votes) {
- parent.votes = [];
- }
- parent.votes.push(message);
- message.parent_message = message.content.vote.link;
- } else if (message.content.type == 'post') {
- if (message.content.root) {
- if (typeof(message.content.root) === 'string') {
- let m = self.ensure_message(message.content.root);
- if (!m.child_messages) {
- m.child_messages = [];
- }
- m.child_messages.push(message);
- message.parent_message = message.content.root;
- } else {
- let m = self.ensure_message(message.content.root[0]);
- if (!m.child_messages) {
- m.child_messages = [];
- }
- m.child_messages.push(message);
- message.parent_message = message.content.root[0];
- }
- }
- }
- }
-
- for (let message of messages) {
- message.content = JSON.parse(message.content);
- if (!this.messages_by_id[message.id]) {
- this.messages_by_id[message.id] = message;
- link_message(message);
- } else if (this.messages_by_id[message.id].placeholder) {
- let placeholder = this.messages_by_id[message.id];
- this.messages_by_id[message.id] = message;
- message.parent_message = placeholder.parent_message;
- message.child_messages = placeholder.child_messages;
- message.votes = placeholder.votes;
- if (placeholder.parent_message && this.messages_by_id[placeholder.parent_message]) {
- let children = this.messages_by_id[placeholder.parent_message].child_messages;
- children.splice(children.indexOf(placeholder), 1);
- children.push(message);
- }
- link_message(message);
- }
- }
- }
-
- async load_placeholders() {
- let placeholders = Object.values(this.messages_by_id).filter(x => x.placeholder).map(x => x.id);
- return await tfrpc.rpc.query(
- `
- SELECT messages.* FROM messages
- JOIN json_each(?) AS placeholder ON messages.id = placeholder.value
- JOIN json_each(?) AS following ON messages.author = following.value
- ORDER BY messages.timestamp DESC
- `,
- [
- JSON.stringify(placeholders),
- JSON.stringify(this.allFollowing),
- ]);
- }
-
- async finalize_messages() {
- this.process_messages(await this.load_placeholders());
- function recursive_sort(messages, top) {
- if (messages) {
- if (top) {
- messages.sort((a, b) => b.timestamp - a.timestamp);
- } else {
- messages.sort((a, b) => a.timestamp - b.timestamp);
- }
- for (let message of messages) {
- recursive_sort(message.child_messages, false);
- }
- return messages.map(x => Object.assign({}, x));
- }
- }
- this.messages =
- recursive_sort(
- Object.values(this.messages_by_id)
- .filter(x => !x.parent_message),
- true);
- }
-
- async load() {
- if (this.loading || (!this.whoami && this.ids.length)) {
- return;
- }
- let load_button = this.renderRoot.getElementById('load_button');
- this.loading = true;
- if (load_button) {
- load_button.disabled = true;
- }
- this.status = [];
- this.messages = [];
- this.messages_by_id = {};
- this.users = {};
- this.allFollowing = [];
- console.log('loading...', this.hash);
- this.record_status('loading');
- this.record_status('getting following');
- this.allFollowing = await this.following_deep([this.whoami], 2, {});
- console.log('following', this.allFollowing.length, 'identities');
- this.record_status('getting about');
- await this.fetch_about(this.allFollowing.sort());
- this.record_status('getting messages');
- this.process_messages(await this.fetch_messages());
- await this.finalize_messages();
- this.record_status('done');
- this.status = [];
- if (load_button) {
- load_button.disabled = false;
- }
- this.loading = false;
- }
-
_handle_whoami_changed(event) {
- this.whoami = event.srcElement.selected;
- this.load();
+ if (this.whoami !== event.srcElement.selected) {
+ console.log('whoami changed', event.srcElement.selected);
+ this.whoami = event.srcElement.selected;
+ }
}
- async search(event) {
- this.messages = [];
- this.messages_by_id = {};
- let query = this.renderRoot.getElementById('search').value;
- console.log('Searching...');
- let results = await tfrpc.rpc.query(`
- SELECT messages.*
- FROM messages_fts(?)
- JOIN messages ON messages.rowid = messages_fts.rowid
- JOIN json_each(?) AS following ON messages.author = following.value
- ORDER BY timestamp DESC limit 100
- `,
- [query, JSON.stringify(this.allFollowing)]);
- console.log('Done.');
- this.process_messages(results);
- await this.finalize_messages();
- this.renderRoot.getElementById('search').value = '';
+ async create_identity() {
+ if (confirm("Are you sure you want to create a new identity?")) {
+ await tfrpc.rpc.createIdentity();
+ this.requestUpdate();
+ }
}
- search_keydown(event) {
- if (event.keyCode == 13) {
- this.search();
+ async render_id_picker() {
+ this._ids = this._ids || (await tfrpc.rpc.getIdentities()) || [];
+ return html`
+