Skip to content

Commit

Permalink
import GPS location annotation for text/sketch/voice posts; improve d…
Browse files Browse the repository at this point in the history
…escription of productivity tools
  • Loading branch information
tschudin committed Aug 5, 2024
1 parent b4ea5f4 commit abd7bbb
Show file tree
Hide file tree
Showing 11 changed files with 356 additions and 49 deletions.
1 change: 1 addition & 0 deletions android/tinySSB/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ dependencies {

// database
implementation "androidx.room:room-runtime:2.3.0"
implementation 'com.google.android.gms:play-services-location:18.0.0' // 21.3.0'
kapt "androidx.room:room-compiler:2.3.0"
// implementation "androidx.room:room-rxjava2:2.3.0"
// implementation "androidx.room:room-guava:2.3.0"
Expand Down
52 changes: 49 additions & 3 deletions android/tinySSB/app/src/main/assets/web/prod/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,13 @@ function new_text_post(s) {
if (s.length == 0) {
return;
}
var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
var draft = ''
if (Android.isGeoLocationEnabled() == "true") {
var plusCode = Android.getCurrentLocationAsPlusCode();
if (plusCode != null && plusCode.length > 0) //check if we actually received a location
draft += "pfx:loc/plus," + plusCode + "|";
}
draft += unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
var ch = tremola.chats[curr_chat]
if (!(ch.timeline instanceof Timeline)) {
ch.timeline = Timeline.fromJSON(ch.timeline)
Expand All @@ -92,7 +98,13 @@ function new_text_post(s) {
}

function new_voice_post(voice_b64) {
var draft = unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
var draft = ''
if (Android.isGeoLocationEnabled() == "true") {
var plusCode = Android.getCurrentLocationAsPlusCode();
if (plusCode != null && plusCode.length > 0) //check if we actually received a location
draft += "pfx:loc/plus," + plusCode + "|";
}
draft += unicodeStringToTypedArray(document.getElementById('draft').value); // escapeHTML(
if (draft.length == 0)
draft = "null"
else
Expand Down Expand Up @@ -144,16 +156,48 @@ function new_image_post() {
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 = "<div class=light style='padding: 3pt; border-radius: 4px; box-shadow: 0 0 5px rgba(0,0,0,0.7); word-break: break-word;'"
if (p.voice != null)
box += " onclick='play_voice(\"" + curr_chat + "\", \"" + p.key + "\");'";
*/
var box = "<div class=light style='padding: 3pt; border-radius: 4px; box-shadow: 0 0 5px rgba(0,0,0,0.7); word-break: break-word;'";
var textOfBody = escapeHTML(p["body"]).replace(/\n/g, "<br>\n");
// split each message, so that we may access the fields of the message
var fieldsOfBody = textOfBody.split(/(\|)/g);
var geoLocPlusCode = null;
// here we check all prefixes that might be in a message, it is currently not possible to send a sketch with any prefixes since this completely breaks the sketch because uses the character '|'
var i = 0;
var otherText = "";
while (i < fieldsOfBody.length){
var field = fieldsOfBody[i];
if (field.startsWith("pfx:loc/plus")){
var partsOfGeoLoc = field.split(',');
geoLocPlusCode = partsOfGeoLoc[1];
i++;
} else {
otherText += field;
}
i++;
}
if ((p.voice != null) && geoLocPlusCode == null)
box += " onclick='play_voice(\"" + curr_chat + "\", \"" + p.key + "\");'";
if ((geoLocPlusCode != null) && (p.voice == null))
box += " onclick='showGeoMenu(\"" + geoLocPlusCode + "\");'";
if ((geoLocPlusCode != null) && (p.voice != null))
box += " onclick='showGeoVoiceMenu(\"" + geoLocPlusCode + "\",\"" + curr_chat + "\", \"" + p.key + "\");'";

box += ">"

// console.log("box=", box);
if (is_other)
box += "<font size=-1><i>" + fid2display(p["from"]) + "</i></font><br>";
// if (geoLocPlusCode != null)
// box += "<font size=-4><i>" + "this message contains geolocation" + "</i></font><br>";
var txt = ""
if (p["body"] != null) {
txt = escapeHTML(p["body"]).replace(/\n/g, "<br>\n");
// txt = escapeHTML(p["body"]).replace(/\n/g, "<br>\n");
txt = otherText;
// Sketch app
if (txt.startsWith("data:image/png;base64")) { // check if the string is a data url
let compressedBase64 = txt.split(',')[1];
Expand Down Expand Up @@ -231,6 +275,8 @@ function load_post_item(p) { // { 'key', 'from', 'when', 'body', 'to' (if group
box += txt
var d = new Date(p["when"]);
d = d.toDateString() + ' ' + d.toTimeString().substring(0, 5);
if (geoLocPlusCode != null)
d = '📌 ' + d
box += "<div align=right style='font-size: x-small;'><i>";
box += d + "</i></div></div>";
var row;
Expand Down
9 changes: 6 additions & 3 deletions android/tinySSB/app/src/main/assets/web/prod/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,17 @@ const BrowserOnlySettings = {
'hide_forgotten_kanbans': true,
'udp_multicast_enabled': true,
'ble_enabled': true,
'websocket_url': "ws://meet.dmi.unibas.ch:8989"
'websocket_url': "ws://meet.dmi.unibas.ch:8989",
'geo_location': true
}

// button/toggle handler for boolean settings; settingID is determined by the id of the html object that emitted the event (e.id)
function toggle_changed(e) {
// console.log("toggle ", e.id);
console.log("toggle:", e.id);
tremola.settings[e.id] = e.checked;
backend("settings:set " + e.id + " " + e.checked)
var cmd = "settings:set " + e.id + " " + e.checked
backend(cmd)
console.log(`sent "${cmd}" to backend`)
persist()
applySetting(e.id, e.checked);
}
Expand Down
62 changes: 36 additions & 26 deletions android/tinySSB/app/src/main/assets/web/prod/sketch.js
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,7 @@ async function sketch_get_current_size() {

// return the current sketch as a base64 string (including the preceding data type descriptor)
async function sketch_getImage() {
// console.log('getImage', JSON.stringify(sketch.svg));
console.log('getImage', JSON.stringify(sketch.svg));
const buf = new ArrayBuffer(bipf_encodingLength(sketch.svg))
const e = bipf_encode(sketch.svg, buf, 0)
// console.log(' bipf:', JSON.stringify(new Uint8Array(buf)))
Expand Down Expand Up @@ -474,40 +474,50 @@ async function sketch_getImage() {
for (var i = 0; i < len; i++) {
binary += String.fromCharCode( bytes[ i ] );
}

let shortenedDataURL = 'data:image/svg+bipf;base64,' + btoa(binary);

return shortenedDataURL
}

//function called by the drawing submit button
async function chat_sendDrawing() {
let img = await sketch_getImage()
if (img.length == 0) {
var img = await sketch_getImage()
if (img.length == 0)
return;
}

// send to backend
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())
if (curr_chat == "ALL") {
var cmd = `publ:post ${tips} ` + btoa(img) + " null"; // + recps
// console.log(cmd)
backend(cmd);
} else {
var recps = tremola.chats[curr_chat].members.join(' ');
var cmd = `priv:post ${tips} ` + btoa(img) + " null " + recps;
backend(cmd);
}
launch_snackbar("sending sketch ...")
setTimeout(function () { // delay sending (and getting location beforehand), allows snackbar to show

//add geolocation to message if enabled.
if (Android.isGeoLocationEnabled() == "true"){ //ony add if enabled
var plusCode = Android.getCurrentLocationAsPlusCode();
if (plusCode != null && plusCode.length > 0) //check if we actually received a location
img = "pfx:loc/plus," + plusCode + "|" + img;
}

// send to backend
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())
if (curr_chat == "ALL") {
var cmd = `publ:post ${tips} ` + btoa(img) + " null"; // + recps
// console.log(cmd)
backend(cmd);
} else {
var recps = tremola.chats[curr_chat].members.join(' ');
var cmd = `priv:post ${tips} ` + btoa(img) + " null " + recps;
backend(cmd);
}

closeOverlay();
// setTimeout(function () { // let image rendering (fetching size) take place before we scroll
let c = document.getElementById('core');
c.scrollTop = c.scrollHeight;
// }, 100);
closeOverlay();
// setTimeout(function () { // let image rendering (fetching size) take place before we scroll
let c = document.getElementById('core');
c.scrollTop = c.scrollHeight;
// }, 100);

// close sketch
chat_closeSketch();
// close sketch
chat_closeSketch();
}, 100);
}
8 changes: 4 additions & 4 deletions android/tinySSB/app/src/main/assets/web/prod/tools.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
function load_prod_list() {
document.getElementById("lst:prod").innerHTML = '';
load_prod_item('Kanban', 'img/kanban.svg', 'setScenario("kanban")',
'text text text h aghjwd gldfhjs hlgsf hgljksf hgls fdhglf sdhgl hfgskj hls dfhgjl shgjkls hgl sfdhgjk sdfjklg hljs hfgl dfjlsfs');
'Collaboratively visualize your work items and give participants a view of progress and process, from start to finish.<br>Author: Jannick Heisch');
load_prod_item('Event Scheduler (dpi24.14)', 'img/schedule.svg', 'setScenario("scheduling")',
'text text text h aghjwd gldfhjs hlgsf hgljksf hgls fdhglf sdhgl hfgskj hls dfhgjl shgjkls hgl sfdhgjk sdfjklg hljs hfgl dfjlsfs');
'Collaboratively find suitable dates by collecting availability of participants.<br>Authors: Sascha Schumacher and Jasra Mohamed Yoosuf');
load_prod_item('Kahoot Quiz (dpi24.15)', 'img/quiz.svg', 'xyz',
'text text text h aghjwd gldfhjs hlgsf hgljksf hgls fdhglf sdhgl hfgskj hls dfhgjl shgjkls hgl sfdhgjk sdfjklg hljs hfgl dfjlsfs');
'Create and participate in quizzes - a fun way for users to test their knowledge and learn new information.<br>Authors: Anoozh Akileswaran, Prabavan Balasubramaniam and Jakob Spiess');
load_prod_item('Lokens (coming soon)', 'img/hand_and_coins.svg', 'xyz',
'see Erick Lavoie: "GOC-Ledger: State-based Conflict-Free Replicated Ledger from Grow-Only Counters", https://arxiv.org/abs/2305.16976');
}
Expand All @@ -21,7 +21,7 @@ function load_prod_item(title, imageName, cb, descr) {
row = `<button class="app_icon" style="margin-right: 0.75em; background-color: white;"><img width=35 height=35 src="${imageName}"/>`;
row += `<button class='prod_item_button light' style='overflow: hidden; width: calc(100% - 4em);' onclick='${cb};'>`;
row += "<div style='white-space: wrap;'><div style='text-overflow: ellipsis; overflow: hidden;'>" + escapeHTML(title) + "</div>";
row += "<font size=-2>" + escapeHTML(descr) + "</font></div></button>";
row += "<font size=-2>" + descr + "</font></div></button>";
item.innerHTML = row;
document.getElementById('lst:prod').appendChild(item);
}
Expand Down
17 changes: 17 additions & 0 deletions android/tinySSB/app/src/main/assets/web/tremola.css
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,22 @@ textarea {
box-shadow: 0 0 25px rgba(0,0,0,0.9);
}

.geo-menu-overlay {
display: none;
position: absolute;
left: 50%;
top: 20%;
transform: translateX(-50%);
width: auto;
max-width: 90%;
min-width: 70%;
background: #fff;
padding: 0.5em;
z-index: 10002; /* high z-index */
border-radius: 5px;
box-shadow: 0 0 25px rgba(0,0,0,0.9);
}

.qr-overlay {
display: none;
background: #fff;
Expand Down Expand Up @@ -516,4 +532,5 @@ input:checked + .slider:before {
filter: invert(62%) sepia(8%) saturate(116%) hue-rotate(145deg) brightness(89%) contrast(89%);
}


/* eof */
34 changes: 26 additions & 8 deletions android/tinySSB/app/src/main/assets/web/tremola.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,14 @@
<body style="background-image: url('img/splash-as-background.jpg'); background-size: cover; background-color: white; overflow: hidden" onload="backend('ready');">
<div style="width: 100%; height: 100%; margin: 0px">

<div id='menu' class='menu-overlay'>
<!-- <button onclick="delete_chat_item();">Delete this chat</button><br>
<button>item2</button><br>
<button>item3</button> -->
</div>
<div id='menu' class='menu-overlay'>
<!-- <button onclick="delete_chat_item();">Delete this chat</button><br>
<button>item2</button><br>
<button>item3</button> -->
</div>

<div id='geo-menu' class='geo-menu-overlay'>
</div>

<div id='attach-menu' class='attach-menu-overlay'>
<button class="attach-menu-item-button" onclick="chat_openSketch();">create sketch</button>
Expand Down Expand Up @@ -64,7 +67,7 @@
</div>
<div><button id='btn:menu' class="flat neutral" onclick="btnBridge(this);" style="vertical-align: top; background-color: transparent; padding-top: 3pt;"><font size=+1>&nbsp;<strong>&#9776;</strong>&nbsp;</font></button></div>
</div>
</div>
</div>

<div id='core' style="height: calc(100% - 118px); width: 100%;">

Expand Down Expand Up @@ -489,6 +492,11 @@ <h2>Game Invitation declined</h2>
Etienne Mettaz<br>
Cedrik Schimschar<br>
Christian Tschudin<br>
<br>
Students of DPI.fs24:<br>
Luca Gloor<br>
Anna Pietzak<br>
Pius Walser
&nbsp;

<p>Icons<br>
Expand Down Expand Up @@ -566,12 +574,21 @@ <h2>Game Invitation declined</h2>
</div>
</div>

<div id="div:settings" style="display: none; height: calc(100% - 45px);"><div style="height: 100%; overflow: scroll; margin: 6px;">
<div id="div:settings" style="display: none; height: calc(100% - 45px); overflow-y: scroll; overflow-x: hidden; margin: 6px;">
<div style="text-align: center;"><em>Configurations</em></div>
<hr>

<!-- TOGGLES -->

<div class="settings">
<div class="settingsText">Send current location with messages</div>
<div style="float: right;"><label class="switch">
<input id="geo_location_enabled" type="checkbox" onchange="toggle_changed(this);">
<span class="slider round"></span></label>
</div>
</div>
<hr>

<div class="settings">
<div class="settingsText">Connect to Peers via BLE</div>
<div style="float: right;"><label class="switch">
Expand All @@ -595,6 +612,7 @@ <h2>Game Invitation declined</h2>
<input id="websocket_enabled" type="checkbox" onchange="toggle_changed(this);">
<span class="slider round"></span></label></div>
</div>

<div id="container:settings_ws_url" class="websocket_url_settings" style="display:none;">
<div class="settingsText" style="margin-right: 10px;font-size: 16px;margin-bottom: 5px;">URL: </div>
<input type="text" id="settings_urlInput" onkeypress="onEnter(event)" placeholder="Websocket-Url (ws://...)" required style="height:30px; width: 70%">
Expand Down Expand Up @@ -669,7 +687,7 @@ <h2>Game Invitation declined</h2>
<p>&nbsp;<br>&nbsp;<br>&nbsp;<br><button class="w100 button active item" style="height: 2.5em;" onclick="settings_wipe();">
<span style="color: #e85132 /* var(--red) */;font-weight: 900;">WIPE EVERYTHING IMMEDIATELY</span></button><hr>
&nbsp;
</div></div>
</div>

</div>

Expand Down
Loading

0 comments on commit abd7bbb

Please sign in to comment.