diff --git a/android/tinySSB/app/src/main/assets/web/prod/chat.js b/android/tinySSB/app/src/main/assets/web/prod/chat.js
new file mode 100644
index 0000000..58f0430
--- /dev/null
+++ b/android/tinySSB/app/src/main/assets/web/prod/chat.js
@@ -0,0 +1,414 @@
+// prod/chat.js
+
+"use strict";
+
+var curr_chat;
+var curr_img_candidate = null;
+// var restream = false // whether the backend is currently restreaming all posts
+
+// --- menu callbacks
+
+function menu_new_conversation() {
+ fill_members();
+ prev_scenario = 'chats';
+ setScenario("members");
+ document.getElementById("div:textarea").style.display = 'none';
+ document.getElementById("div:confirm-members").style.display = 'flex';
+ document.getElementById("tremolaTitle").style.display = 'none';
+ var c = document.getElementById("conversationTitle");
+ c.style.display = null;
+ c.innerHTML = "Create Private Channel Select up to 7 members";
+ document.getElementById('plus').style.display = 'none';
+ closeOverlay();
+}
+
+function menu_edit_convname() {
+ menu_edit('convNameTarget', "Edit conversation name: (only you can see this name)", tremola.chats[curr_chat].alias);
+}
+
+function menu_forget_conv() {
+ // toggles the forgotten flag of a conversation
+ if (curr_chat == recps2nm([myId])) {
+ launch_snackbar("cannot be applied to own notes");
+ return;
+ }
+ tremola.chats[curr_chat].forgotten = !tremola.chats[curr_chat].forgotten;
+ persist();
+ load_chat_list() // refresh list of conversations
+ closeOverlay();
+ if (curr_scenario == 'posts' /* should always be true */ && tremola.chats[curr_chat].forgotten)
+ setScenario('chats');
+ else
+ load_chat(curr_chat) // refresh currently displayed list of posts
+}
+
+/* ??
+function menu_take_picture() {
+ disabled6676863(); // breakpoint using a non-existing fct,in case
+ closeOverlay();
+ var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
+ if (draft.length == 0)
+ draft = null;
+ else
+ draft = atob(draft);
+ console.log("getVoice" + document.getElementById('draft').value);
+ backend('get:voice ' + atob(draft));
+}
+
+function menu_pick_image() {
+ closeOverlay();
+ backend('get:media');
+}
+*/
+
+// --- workflow entry points
+
+function new_text_post(s) {
+ if (s.length == 0) {
+ return;
+ }
+ var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
+ var ch = tremola.chats[curr_chat]
+ if (!(ch.timeline instanceof Timeline)) {
+ ch.timeline = Timeline.fromJSON(ch.timeline)
+ }
+ let tips = JSON.stringify(ch.timeline.get_tips())
+ // console.log(`tips: ${tips}`)
+ if (curr_chat == "ALL") {
+ var cmd = `publ:post ${tips} ` + btoa(draft) + " null"; // + recps
+ // console.log(cmd)
+ backend(cmd);
+ } else {
+ var recps = tremola.chats[curr_chat].members.join(' ');
+ var cmd = `priv:post ${tips} ` + btoa(draft) + " null " + recps;
+ backend(cmd);
+ }
+ document.getElementById('draft').value = '';
+ closeOverlay();
+ setTimeout(function () { // let image rendering (fetching size) take place before we scroll
+ var c = document.getElementById('core');
+ c.scrollTop = c.scrollHeight;
+ }, 100);
+}
+
+function new_voice_post(voice_b64) {
+ var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
+ if (draft.length == 0)
+ draft = "null"
+ else
+ draft = btoa(draft)
+ var ch = tremola.chats[curr_chat]
+ if (!(ch.timeline instanceof Timeline)) {
+ ch.timeline = Timeline.fromJSON(ch.timeline)
+ }
+ let tips = JSON.stringify(ch.timeline.get_tips())
+ // console.log(`tips: ${tips}`)
+
+ if (curr_chat == "ALL") {
+ var cmd = `publ:post ${tips} ` + draft + " " + voice_b64;
+ // console.log(cmd)
+ backend(cmd);
+ } else {
+ var recps = tremola.chats[curr_chat].members.join(' ');
+ var cmd = `priv:post ${tips} ` + draft + " " + voice_b64 + " " + recps;
+ backend(cmd);
+ }
+ document.getElementById('draft').value = '';
+}
+
+function play_voice(nm, ref) {
+ var p = tremola.chats[nm].posts[ref];
+ var d = new Date(p["when"]);
+ d = d.toDateString() + ' ' + d.toTimeString().substring(0, 5);
+ backend("play:voice " + p["voice"] + " " + btoa(fid2display(p["from"])) + " " + btoa(d));
+}
+
+function new_image_post() {
+ if (curr_img_candidate == null) {
+ return;
+ }
+ var draft = "![](" + curr_img_candidate + ")\n";
+ var caption = document.getElementById('image-caption').value;
+ if (caption && caption.length > 0)
+ draft += caption;
+ var recps = tremola.chats[curr_chat].members.join(' ')
+ backend("priv:post " + btoa(draft) + " " + recps);
+ curr_img_candidate = null;
+ closeOverlay();
+ setTimeout(function () { // let image rendering (fetching size) take place before we scroll
+ var c = document.getElementById('core');
+ c.scrollTop = c.scrollHeight;
+ }, 100);
+}
+
+function load_post_item(p) { // { 'key', 'from', 'when', 'body', 'to' (if group or public)>
+ var pl = document.getElementById('lst:posts');
+ var is_other = p["from"] != myId;
+ var box = "
"
+ // console.log("box=", box);
+ if (is_other)
+ box += "" + fid2display(p["from"]) + " ";
+ var txt = ""
+ if (p["body"] != null) {
+ txt = escapeHTML(p["body"]).replace(/\n/g, " \n");
+ // Sketch app
+ if (txt.startsWith("data:image/png;base64")) { // check if the string is a data url
+ let compressedBase64 = txt.split(',')[1];
+ // We Convert the compressed data from a base64 string to a Uint8Array
+ let compressedData = atob(compressedBase64)
+ .split('')
+ .map(function (char) {
+ return char.charCodeAt(0);
+ });
+ let uint8Array = new Uint8Array(compressedData);
+
+ // We to decompress the Uint8Array
+ let decompressedData = pako.inflate(uint8Array);
+ // We Convert the decompressed data back to a base64 string
+ let decompressedBase64 = btoa(String.fromCharCode.apply(null, decompressedData));
+ // We Create a new data URL with the decompressed data
+ let decompressedDataURL = 'data:image/png;base64,' + decompressedBase64;
+ //display the data url as an image element
+ box += "";
+ txt = "";
+ } else if (txt.startsWith("data:image/svg+bipf;base64")) {
+ let b64 = txt.split(',')[1];
+ var binStr = atob(b64)
+ var buf = new ArrayBuffer(binStr.length);
+ var ui8 = new Uint8Array(buf);
+ for (var i = 0; i < binStr.length; i++)
+ ui8[i] = binStr.charCodeAt(i);
+ var src;
+ try {
+ let img = bipf_decode(buf, 0);
+ // console.log('got svg', JSON.stringify(img));
+ // img[0] -- version of this svg encoding, currently 1, ignored
+ if (Number.isInteger(img[0]))
+ img = img.slice(1)
+ var svg = `';
+ // console.log('svg:', svg)
+ src = `data:image/svg+xml;base64,${btoa(svg)}`;
+ } catch (error) {
+ console.error(error);
+ src = "data:null";
+ }
+ box += `';
+ txt = "";
+ }
+
+ var re = /!\[.*?\]\((.*?)\)/g;
+ txt = txt.replace(re, " ");
+ // txt = txt + " (!)";
+ // console.log(txt);
+ }
+ if (p.voice != null)
+ box += "🔊 "
+ box += txt
+ var d = new Date(p["when"]);
+ d = d.toDateString() + ' ' + d.toTimeString().substring(0, 5);
+ box += "
";
+ box += d + "
";
+ var row;
+ if (is_other) {
+ var c = tremola.contacts[p.from]
+ row = "
";
+ curr_chat = nm;
+ for (var n of ch.timeline.linear) {
+ load_post_item(ch.posts[n.name])
+ }
+ /*
+ var lop = []; // list of posts
+ for (var p in ch.posts) lop.push(p)
+ lop.sort(function (a, b) {
+ return ch.posts[a].when - ch.posts[b].when
+ })
+ lop.forEach(function (p) {
+ load_post_item(ch.posts[p])
+ })
+ */
+ load_chat_title(ch);
+ setScenario("posts");
+ document.getElementById("tremolaTitle").style.display = 'none';
+ // update unread badge:
+ ch["lastRead"] = Date.now();
+ persist();
+ document.getElementById(nm + '-badge').style.display = 'none' // is this necessary?
+ /*
+ // scroll to bottom:
+ var c = document.getElementById('core');
+ c.scrollTop = c.scrollHeight;
+ document.getElementById('lst:posts').scrollIntoView(false)
+ // console.log("did scroll down, but did it do it?")
+ */
+}
+
+function load_chat_title(ch) {
+ var c = document.getElementById("conversationTitle"), bg, box;
+ c.style.display = null;
+ c.setAttribute('classList', ch.forgotten ? 'gray' : '') // old JS (SDK 23)
+ box = "
" + escapeHTML(ch.alias) + "
";
+ var mem = "[ALL]"
+ if (ch.members.length > 1 || ch.members[0] != "ALL")
+ mem = "🔒 " + recps2display(ch.members)
+ box += "
" + escapeHTML(mem) + "
";
+ c.innerHTML = box;
+}
+
+function load_chat_list() {
+ document.getElementById('lst:chats').innerHTML = '';
+ load_chat_item("ALL")
+ var meOnly = recps2nm([myId])
+ if (!(meOnly in tremola.chats)) {
+ tremola.chats[meOnly] = {
+ "alias": "--- local notes (for my eyes only)", "posts": {}, "forgotten": false,
+ "members": [myId], "touched": Date.now(), "lastRead": 0,
+ "timeline": new Timeline()
+ };
+ }
+ load_chat_item(meOnly)
+ var lop = [];
+ for (var p in tremola.chats) {
+ if (p != "ALL" && p != meOnly && !tremola.chats[p]['forgotten'])
+ lop.push(p)
+ }
+ lop.sort(function (a, b) {
+ return tremola.chats[b]["touched"] - tremola.chats[a]["touched"]
+ })
+ lop.forEach(function (p) {
+ load_chat_item(p)
+ })
+ // forgotten chats: unsorted
+ if (!tremola.settings.hide_forgotten_conv)
+ for (var p in tremola.chats)
+ if (p != meOnly && tremola.chats[p]['forgotten'])
+ load_chat_item(p)
+}
+
+function load_chat_item(nm) { // appends a button for conversation with name nm to the conv list
+ var cl, mem, item, bg, row, badge, badgeId, cnt;
+ cl = document.getElementById('lst:chats');
+ // console.log(nm)
+ if (nm == "ALL")
+ mem = "ALL";
+ else
+ mem = "🔒 " + recps2display(tremola.chats[nm].members);
+ item = document.createElement('div');
+ // item.style = "padding: 0px 5px 10px 5px; margin: 3px 3px 6px 3px;";
+ item.setAttribute('class', 'chat_item_div'); // old JS (SDK 23)
+ if (tremola.chats[nm].forgotten) bg = ' gray'; else bg = ' light';
+ row = "";
+ row += ""
+ item.innerHTML = row;
+ cl.appendChild(item);
+ set_chats_badge(nm)
+}
+
+function new_conversation() {
+ // { "alias":"local notes (for my eyes only)", "posts":{}, "members":[myId], "touched": millis }
+ var recps = []
+ for (var m in tremola.contacts) {
+ if (document.getElementById(m).checked)
+ recps.push(m);
+ }
+ if (recps.indexOf(myId) < 0)
+ recps.push(myId);
+ if (recps.length > 7) {
+ launch_snackbar("Too many recipients");
+ return;
+ }
+ var cid = recps2nm(recps)
+ if (cid in tremola.chats) {
+ if (tremola.chats[cid].forgotten) {
+ tremola.chats[cid].forgotten = false;
+ load_chat_list(); // refresh
+ } else
+ launch_snackbar("Conversation already exists");
+ return;
+ }
+ var nm = recps2nm(recps);
+ if (!(nm in tremola.chats)) {
+ tremola.chats[nm] = {
+ "alias": "Private", "posts": {},
+ "members": recps, "touched": Date.now(),
+ "timeline": new Timeline()
+ };
+ persist();
+ } else
+ tremola.chats[nm]["touched"] = Date.now()
+ load_chat_list();
+ setScenario("chats")
+ curr_chat = nm
+ menu_edit_convname()
+}
+
+function getUnreadCnt(nm) {
+ var c = tremola.chats[nm], cnt = 0;
+ for (var p in c.posts) {
+ if (c.posts[p].when > c.lastRead)
+ cnt++;
+ }
+ return cnt;
+}
+
+function set_chats_badge(nm) {
+ var e = document.getElementById(nm + '-badge'), cnt;
+ cnt = getUnreadCnt(nm)
+ if (cnt == 0) {
+ e.style.display = 'none';
+ return
+ }
+ e.style.display = null;
+ if (cnt > 9) cnt = ">9"; else cnt = "" + cnt;
+ e.innerHTML = cnt
+}
+
+// --- eof
diff --git a/android/tinySSB/app/src/main/assets/web/prod/contacts.js b/android/tinySSB/app/src/main/assets/web/prod/contacts.js
new file mode 100644
index 0000000..74ee980
--- /dev/null
+++ b/android/tinySSB/app/src/main/assets/web/prod/contacts.js
@@ -0,0 +1,146 @@
+// prod/contacts.js
+
+"use strict";
+
+var new_contact_id = '';
+
+// --- menu callbacks
+
+function menu_new_contact() {
+ document.getElementById('new_contact-overlay').style.display = 'initial';
+ document.getElementById('overlay-bg').style.display = 'initial';
+ // document.getElementById('chat_name').focus();
+ overlayIsActive = true;
+}
+
+function menu_import_id() {
+ closeOverlay();
+ document.getElementById('import-id-overlay').style.display = 'initial'
+ document.getElementById('overlay-bg').style.display = 'initial'
+}
+
+function btn_import_id() {
+ var str = document.getElementById('import-id-input').value
+ if(str == "")
+ return
+ var r = import_id(str)
+ if(r) {
+ launch_snackbar("Successfully imported, restarting...")
+ } else {
+ launch_snackbar("wrong format")
+ }
+}
+
+function load_contact_list() {
+ document.getElementById("lst:contacts").innerHTML = '';
+ for (var id in tremola.contacts)
+ if (!tremola.contacts[id].forgotten)
+ load_contact_item([id, tremola.contacts[id]]);
+ if (!tremola.settings.hide_forgotten_contacts)
+ for (var id in tremola.contacts) {
+ var c = tremola.contacts[id]
+ if (c.forgotten)
+ load_contact_item([id, c]);
+ }
+}
+
+function load_contact_item(c) { // [ id, { "alias": "thealias", "initial": "T", "color": "#123456" } ] }
+ var row, item = document.createElement('div'), bg;
+ item.setAttribute('style', 'padding: 0px 5px 10px 5px;'); // old JS (SDK 23)
+ if (!("initial" in c[1])) {
+ c[1]["initial"] = c[1].alias.substring(0, 1).toUpperCase();
+ persist();
+ }
+ if (!("color" in c[1])) {
+ c[1]["color"] = colors[Math.floor(colors.length * Math.random())];
+ persist();
+ }
+ // console.log("load_c_i", JSON.stringify(c[1]))
+ bg = c[1].forgotten ? ' gray' : ' light';
+ row = "";
+ row += "";
+ // var row = "
";
+ // console.log(row);
+ item.innerHTML = row;
+ document.getElementById('lst:contacts').appendChild(item);
+}
+
+function show_contact_details(id) {
+ if (id == myId) {
+ document.getElementById('old_contact_alias_hdr').innerHTML = "Alias: (own name, visible to others)"
+ } else {
+ document.getElementById('old_contact_alias_hdr').innerHTML = "Alias: (only you can see this alias)"
+ }
+ var c = tremola.contacts[id];
+ new_contact_id = id;
+ document.getElementById('old_contact_alias').value = c.alias ? c['alias'] : "";
+ var details = '';
+ details += '
IAM-Alias: ' + (c.iam != "" ? c.iam : "—") + '
\n';
+ details += '
Shortname: ' + id2b32(id) + '
\n';
+ details += '
SSB identity: ' + id + '
\n';
+ details += '
Forget this contact
'
+ document.getElementById('old_contact_details').innerHTML = details;
+ document.getElementById('old_contact-overlay').style.display = 'initial';
+ document.getElementById('overlay-bg').style.display = 'initial';
+ document.getElementById('hide_contact').checked = c.forgotten;
+
+ document.getElementById('old_contact_alias').focus();
+ overlayIsActive = true;
+}
+
+function toggle_forget_contact(e) {
+ var c = tremola.contacts[new_contact_id];
+ c.forgotten = !c.forgotten;
+ persist();
+ closeOverlay();
+ load_contact_list();
+}
+
+function save_content_alias() {
+ var c = tremola.contacts[new_contact_id];
+ var val = document.getElementById('old_contact_alias').value;
+ var deleteAlias = false
+
+ val.trim()
+
+ if (val == '') {
+ deleteAlias = true
+ if (c.iam != "" && new_contact_id != myId) {
+ val = c.iam
+ } else {
+ val = id2b32(new_contact_id);
+ }
+ }
+ var old_alias = c.alias
+ c.alias = val;
+ c.initial = val.substring(0, 1).toUpperCase();
+ c.color = colors[Math.floor(colors.length * Math.random())];
+
+ // update names in connected devices menu
+ for (var l in localPeers) {
+ if (localPeers[l].alias == old_alias) {
+ localPeers[l].alias = val
+ refresh_connection_entry(l)
+ }
+ }
+
+ // share new alias with others via IAM message
+ if(new_contact_id == myId) {
+ if(deleteAlias) {
+ backend("iam " + btoa(""))
+ c.iam = ""
+ } else {
+ backend("iam " + btoa(val))
+ c.iam = val
+ }
+ }
+
+ persist();
+ menu_redraw();
+ closeOverlay();
+}
+
+// --- eof
diff --git a/android/tinySSB/app/src/main/assets/web/tremola_settings.js b/android/tinySSB/app/src/main/assets/web/prod/settings.js
similarity index 99%
rename from android/tinySSB/app/src/main/assets/web/tremola_settings.js
rename to android/tinySSB/app/src/main/assets/web/prod/settings.js
index 922ec3d..ace2332 100644
--- a/android/tinySSB/app/src/main/assets/web/tremola_settings.js
+++ b/android/tinySSB/app/src/main/assets/web/prod/settings.js
@@ -1,8 +1,7 @@
-// tremola_settings.js
+// prod/settings.js
"use strict";
-
// These default settings are only used for browser-only testing
// Normally, these settings below WILL BE IGNORED and loaded via the provided backend.
const BrowserOnlySettings = {
diff --git a/android/tinySSB/app/src/main/assets/web/tremola.html b/android/tinySSB/app/src/main/assets/web/tremola.html
index e3ec280..5cd26f7 100644
--- a/android/tinySSB/app/src/main/assets/web/tremola.html
+++ b/android/tinySSB/app/src/main/assets/web/tremola.html
@@ -6,8 +6,11 @@
-
+
+
+
+
@@ -17,7 +20,6 @@
-
diff --git a/android/tinySSB/app/src/main/assets/web/tremola.js b/android/tinySSB/app/src/main/assets/web/tremola.js
index 9657b8a..79cbafe 100644
--- a/android/tinySSB/app/src/main/assets/web/tremola.js
+++ b/android/tinySSB/app/src/main/assets/web/tremola.js
@@ -3,22 +3,17 @@
"use strict";
var tremola;
-var curr_chat;
-var qr;
var myId;
var localPeers = {}; // feedID ~ [isOnline, isConnected] - TF, TT, FT - FF means to remove this entry
var must_redraw = false;
var edit_target = '';
-var new_contact_id = '';
var colors = ["#d9ceb2", "#99b2b7", "#e6cba5", "#ede3b4", "#8b9e9b", "#bd7578", "#edc951",
"#ffd573", "#c2a34f", "#fbb829", "#ffab03", "#7ab317", "#a0c55f", "#8ca315",
"#5191c1", "#6493a7", "#bddb88"]
-var curr_img_candidate = null;
var pubs = []
-var wants = {}
+// var wants = {}
var loaded_settings = {} // the settings provided bz the backend, will overwrite tremola.settings after initialization
-var restream = false // whether the backend is currently restreaming all posts
// --- menu callbacks
@@ -37,27 +32,6 @@ function menu_sync() {
}
*/
-function menu_new_conversation() {
- fill_members();
- prev_scenario = 'chats';
- setScenario("members");
- document.getElementById("div:textarea").style.display = 'none';
- document.getElementById("div:confirm-members").style.display = 'flex';
- document.getElementById("tremolaTitle").style.display = 'none';
- var c = document.getElementById("conversationTitle");
- c.style.display = null;
- c.innerHTML = "Create Private Channel Select up to 7 members";
- document.getElementById('plus').style.display = 'none';
- closeOverlay();
-}
-
-function menu_new_contact() {
- document.getElementById('new_contact-overlay').style.display = 'initial';
- document.getElementById('overlay-bg').style.display = 'initial';
- // document.getElementById('chat_name').focus();
- overlayIsActive = true;
-}
-
function menu_new_pub() {
menu_edit('new_pub_target', "Enter address of trustworthy pub
Format: net:IP_ADDR:PORT~shs:ID_OF_PUB", "");
}
@@ -106,10 +80,6 @@ function onEnter(ev) {
}
}
-function menu_edit_convname() {
- menu_edit('convNameTarget', "Edit conversation name: (only you can see this name)", tremola.chats[curr_chat].alias);
-}
-
// function menu_edit_new_contact_alias() {
// menu_edit('new_contact_alias', "Assign alias to new contact:", "");
// }
@@ -223,44 +193,12 @@ function members_confirmed() {
}
}
-function menu_forget_conv() {
- // toggles the forgotten flag of a conversation
- if (curr_chat == recps2nm([myId])) {
- launch_snackbar("cannot be applied to own notes");
- return;
- }
- tremola.chats[curr_chat].forgotten = !tremola.chats[curr_chat].forgotten;
- persist();
- load_chat_list() // refresh list of conversations
- closeOverlay();
- if (curr_scenario == 'posts' /* should always be true */ && tremola.chats[curr_chat].forgotten)
- setScenario('chats');
- else
- load_chat(curr_chat) // refresh currently displayed list of posts
-}
-
-function menu_import_id() {
- closeOverlay();
- document.getElementById('import-id-overlay').style.display = 'initial'
- document.getElementById('overlay-bg').style.display = 'initial'
-}
-
-function btn_import_id() {
- var str = document.getElementById('import-id-input').value
- if(str == "")
- return
- var r = import_id(str)
- if(r) {
- launch_snackbar("Successfully imported, restarting...")
- } else {
- launch_snackbar("wrong format")
- }
-}
-
+/*
function menu_process_msgs() {
backend('process.msg');
closeOverlay();
}
+*/
function menu_add_pub() {
// ...
@@ -272,351 +210,6 @@ function menu_dump() {
closeOverlay();
}
-function menu_take_picture() {
- disabled6676863(); // breakpoint using a non-existing fct,in case
- closeOverlay();
- var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
- if (draft.length == 0)
- draft = null;
- else
- draft = atob(draft);
- console.log("getVoice" + document.getElementById('draft').value);
- backend('get:voice ' + atob(draft));
-}
-
-function menu_pick_image() {
- closeOverlay();
- backend('get:media');
-}
-
-// ---
-
-function new_text_post(s) {
- if (s.length == 0) {
- return;
- }
- var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
- var ch = tremola.chats[curr_chat]
- if (!(ch.timeline instanceof Timeline)) {
- ch.timeline = Timeline.fromJSON(ch.timeline)
- }
- let tips = JSON.stringify(ch.timeline.get_tips())
- // console.log(`tips: ${tips}`)
- if (curr_chat == "ALL") {
- var cmd = `publ:post ${tips} ` + btoa(draft) + " null"; // + recps
- // console.log(cmd)
- backend(cmd);
- } else {
- var recps = tremola.chats[curr_chat].members.join(' ');
- var cmd = `priv:post ${tips} ` + btoa(draft) + " null " + recps;
- backend(cmd);
- }
- document.getElementById('draft').value = '';
- closeOverlay();
- setTimeout(function () { // let image rendering (fetching size) take place before we scroll
- var c = document.getElementById('core');
- c.scrollTop = c.scrollHeight;
- }, 100);
-}
-
-function new_voice_post(voice_b64) {
- var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
- if (draft.length == 0)
- draft = "null"
- else
- draft = btoa(draft)
- var ch = tremola.chats[curr_chat]
- if (!(ch.timeline instanceof Timeline)) {
- ch.timeline = Timeline.fromJSON(ch.timeline)
- }
- let tips = JSON.stringify(ch.timeline.get_tips())
- // console.log(`tips: ${tips}`)
-
- if (curr_chat == "ALL") {
- var cmd = `publ:post ${tips} ` + draft + " " + voice_b64;
- // console.log(cmd)
- backend(cmd);
- } else {
- var recps = tremola.chats[curr_chat].members.join(' ');
- var cmd = `priv:post ${tips} ` + draft + " " + voice_b64 + " " + recps;
- backend(cmd);
- }
- document.getElementById('draft').value = '';
-}
-
-function play_voice(nm, ref) {
- var p = tremola.chats[nm].posts[ref];
- var d = new Date(p["when"]);
- d = d.toDateString() + ' ' + d.toTimeString().substring(0, 5);
- backend("play:voice " + p["voice"] + " " + btoa(fid2display(p["from"])) + " " + btoa(d));
-}
-
-function new_image_post() {
- if (curr_img_candidate == null) {
- return;
- }
- var draft = "![](" + curr_img_candidate + ")\n";
- var caption = document.getElementById('image-caption').value;
- if (caption && caption.length > 0)
- draft += caption;
- var recps = tremola.chats[curr_chat].members.join(' ')
- backend("priv:post " + btoa(draft) + " " + recps);
- curr_img_candidate = null;
- closeOverlay();
- setTimeout(function () { // let image rendering (fetching size) take place before we scroll
- var c = document.getElementById('core');
- c.scrollTop = c.scrollHeight;
- }, 100);
-}
-
-function load_post_item(p) { // { 'key', 'from', 'when', 'body', 'to' (if group or public)>
- var pl = document.getElementById('lst:posts');
- var is_other = p["from"] != myId;
- var box = "
"
- // console.log("box=", box);
- if (is_other)
- box += "" + fid2display(p["from"]) + " ";
- var txt = ""
- if (p["body"] != null) {
- txt = escapeHTML(p["body"]).replace(/\n/g, " \n");
- // Sketch app
- if (txt.startsWith("data:image/png;base64")) { // check if the string is a data url
- let compressedBase64 = txt.split(',')[1];
- // We Convert the compressed data from a base64 string to a Uint8Array
- let compressedData = atob(compressedBase64)
- .split('')
- .map(function (char) {
- return char.charCodeAt(0);
- });
- let uint8Array = new Uint8Array(compressedData);
-
- // We to decompress the Uint8Array
- let decompressedData = pako.inflate(uint8Array);
- // We Convert the decompressed data back to a base64 string
- let decompressedBase64 = btoa(String.fromCharCode.apply(null, decompressedData));
- // We Create a new data URL with the decompressed data
- let decompressedDataURL = 'data:image/png;base64,' + decompressedBase64;
- //display the data url as an image element
- box += "";
- txt = "";
- } else if (txt.startsWith("data:image/svg+bipf;base64")) {
- let b64 = txt.split(',')[1];
- var binStr = atob(b64)
- var buf = new ArrayBuffer(binStr.length);
- var ui8 = new Uint8Array(buf);
- for (var i = 0; i < binStr.length; i++)
- ui8[i] = binStr.charCodeAt(i);
- var src;
- try {
- let img = bipf_decode(buf, 0);
- // console.log('got svg', JSON.stringify(img));
- // img[0] -- version of this svg encoding, currently 1, ignored
- if (Number.isInteger(img[0]))
- img = img.slice(1)
- var svg = `';
- // console.log('svg:', svg)
- src = `data:image/svg+xml;base64,${btoa(svg)}`;
- } catch (error) {
- console.error(error);
- src = "data:null";
- }
- box += `';
- txt = "";
- }
-
- var re = /!\[.*?\]\((.*?)\)/g;
- txt = txt.replace(re, " ");
- // txt = txt + " (!)";
- // console.log(txt);
- }
- if (p.voice != null)
- box += "🔊 "
- box += txt
- var d = new Date(p["when"]);
- d = d.toDateString() + ' ' + d.toTimeString().substring(0, 5);
- box += "
";
- box += d + "
";
- var row;
- if (is_other) {
- var c = tremola.contacts[p.from]
- row = "