forked from mirror/monocles_chat_clean
Implement experimental WebXDC "realtime" API
This commit is contained in:
parent
64b969a4bf
commit
359767212d
4 changed files with 91 additions and 14 deletions
|
@ -18,6 +18,7 @@ import android.view.LayoutInflater;
|
|||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.util.Base64;
|
||||
import android.webkit.JavascriptInterface;
|
||||
import android.webkit.ValueCallback;
|
||||
import android.webkit.WebChromeClient;
|
||||
|
@ -37,6 +38,7 @@ import androidx.core.graphics.drawable.IconCompat;
|
|||
import androidx.core.util.Consumer;
|
||||
import androidx.databinding.DataBindingUtil;
|
||||
|
||||
import com.google.android.material.color.MaterialColors;
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import io.ipfs.cid.Cid;
|
||||
|
@ -148,6 +150,13 @@ public class WebxdcPage implements ConversationPage {
|
|||
return "webxdc\0" + source.getUuid();
|
||||
}
|
||||
|
||||
public boolean threadMatches(final Element thread) {
|
||||
if (thread == null) return false;
|
||||
if (thread.getContent() == null) return false;
|
||||
if (source.getThread() == null) return false;
|
||||
return thread.getContent().equals(source.getThread().getContent());
|
||||
}
|
||||
|
||||
public boolean openUri(Uri uri) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
|
@ -301,7 +310,7 @@ public class WebxdcPage implements ConversationPage {
|
|||
TextView tv = (TextView) v.findViewById(android.R.id.text1);
|
||||
tv.setGravity(Gravity.CENTER);
|
||||
tv.setTextColor(ContextCompat.getColor(context, R.color.white));
|
||||
tv.setBackgroundColor(UIHelper.getColorForName(getItem(position)));
|
||||
tv.setBackgroundColor(MaterialColors.harmonizeWithPrimary(activity.get(),UIHelper.getColorForName(getItem(position))));
|
||||
return v;
|
||||
}
|
||||
});
|
||||
|
@ -323,6 +332,7 @@ public class WebxdcPage implements ConversationPage {
|
|||
}
|
||||
ShortcutManagerCompat.requestPinShortcut(xmppConnectionService, builder.build(), null);
|
||||
} else {
|
||||
binding.webview.loadUrl("about:blank");
|
||||
remover.accept(WebxdcPage.this);
|
||||
}
|
||||
});
|
||||
|
@ -336,9 +346,11 @@ public class WebxdcPage implements ConversationPage {
|
|||
}
|
||||
|
||||
public void refresh() {
|
||||
if (binding != null && binding.webview != null) {
|
||||
binding.webview.post(() -> binding.webview.loadUrl("javascript:__webxdcUpdate();"));
|
||||
}
|
||||
|
||||
public void realtimeData(String base64) {
|
||||
binding.webview.post(() -> binding.webview.loadUrl("javascript:__webxdcRealtimeData('" + base64.replace("'", "").replace("\\", "").replace("+", "%2B") + "');"));
|
||||
}
|
||||
|
||||
protected Jid selfJid() {
|
||||
|
@ -353,6 +365,11 @@ public class WebxdcPage implements ConversationPage {
|
|||
protected class InternalJSApi {
|
||||
@JavascriptInterface
|
||||
public String selfAddr() {
|
||||
final Conversation conversation = (Conversation) source.getConversation();
|
||||
if (conversation.getMode() == Conversation.MODE_MULTI && !conversation.getMucOptions().nonanonymous()) {
|
||||
final var occupantId = conversation.getMucOptions().getSelf().getOccupantId();
|
||||
if (occupantId != null) return occupantId;
|
||||
}
|
||||
return "xmpp:" + Uri.encode(selfJid().toEscapedString(), "@/+");
|
||||
}
|
||||
|
||||
|
@ -462,5 +479,20 @@ public class WebxdcPage implements ConversationPage {
|
|||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@JavascriptInterface
|
||||
public void sendRealtime(byte[] data) {
|
||||
Message message = new Message(source.getConversation(), null, Message.ENCRYPTION_NONE);
|
||||
message.addPayload(new Element("no-store", "urn:xmpp:hints"));
|
||||
Element webxdc = new Element("x", "urn:xmpp:webxdc:0");
|
||||
message.addPayload(webxdc);
|
||||
webxdc.addChild("data").setContent(Base64.encodeToString(data, Base64.NO_WRAP));
|
||||
message.setThread(source.getThread());
|
||||
if (source.isPrivateMessage()) {
|
||||
Message.configurePrivateMessage(message, source.getCounterpart());
|
||||
}
|
||||
message.setBody((String) null);
|
||||
xmppConnectionService.sendMessage(message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1702,6 +1702,10 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
|||
pagerAdapter.startWebxdc(page);
|
||||
}
|
||||
|
||||
public void webxdcRealtimeData(final Element thread, final String base64) {
|
||||
pagerAdapter.webxdcRealtimeData(thread, base64);
|
||||
}
|
||||
|
||||
public void startCommand(Element command, XmppConnectionService xmppConnectionService) {
|
||||
pagerAdapter.startCommand(command, xmppConnectionService);
|
||||
}
|
||||
|
@ -1835,6 +1839,18 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
|
|||
}
|
||||
}
|
||||
|
||||
public void webxdcRealtimeData(final Element thread, final String base64) {
|
||||
if (sessions == null) return;
|
||||
|
||||
for (ConversationPage session : sessions) {
|
||||
if (session instanceof WebxdcPage) {
|
||||
if (((WebxdcPage) session).threadMatches(thread)) {
|
||||
((WebxdcPage) session).realtimeData(base64);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void startWebxdc(WebxdcPage page) {
|
||||
show();
|
||||
sessions.add(page);
|
||||
|
|
|
@ -682,16 +682,24 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
|
|||
webxdcSender = counterpart;
|
||||
}
|
||||
}
|
||||
final var document = webxdc.findChildContent("document", "urn:xmpp:webxdc:0");
|
||||
final var summary = webxdc.findChildContent("summary", "urn:xmpp:webxdc:0");
|
||||
final var payload = webxdc.findChildContent("json", "urn:xmpp:json:0");
|
||||
if (document != null || summary != null || payload != null) {
|
||||
mXmppConnectionService.insertWebxdcUpdate(new WebxdcUpdate(
|
||||
conversation,
|
||||
remoteMsgId,
|
||||
counterpart,
|
||||
thread,
|
||||
body == null ? null : body.content,
|
||||
webxdc.findChildContent("document", "urn:xmpp:webxdc:0"),
|
||||
webxdc.findChildContent("summary", "urn:xmpp:webxdc:0"),
|
||||
webxdc.findChildContent("json", "urn:xmpp:json:0")
|
||||
document,
|
||||
summary,
|
||||
payload
|
||||
));
|
||||
}
|
||||
|
||||
final var realtime = webxdc.findChildContent("data", "urn:xmpp:webxdc:0");
|
||||
if (realtime != null) conversation.webxdcRealtimeData(thread, realtime);
|
||||
|
||||
mXmppConnectionService.updateConversationUi();
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ window.webxdc = (() => {
|
|||
let setUpdateListenerPromise = null
|
||||
var update_listener = () => {};
|
||||
var last_serial = 0;
|
||||
var realtime_listener = (data) => {};
|
||||
|
||||
window.__webxdcUpdate = () => {
|
||||
var updates = JSON.parse(InternalJSApi.getStatusUpdates(last_serial));
|
||||
|
@ -18,6 +19,10 @@ window.webxdc = (() => {
|
|||
}
|
||||
};
|
||||
|
||||
window.__webxdcRealtimeData = (data) => {
|
||||
realtime_listener(Uint8Array.from(atob(data), c => c.charCodeAt(0)));
|
||||
};
|
||||
|
||||
return {
|
||||
selfAddr: InternalJSApi.selfAddr(),
|
||||
|
||||
|
@ -112,5 +117,21 @@ window.webxdc = (() => {
|
|||
return Promise.reject(errorMsg);
|
||||
}
|
||||
},
|
||||
|
||||
joinRealtimeChannel: () => {
|
||||
return {
|
||||
leave: () => {},
|
||||
send: (data) => {
|
||||
if (!(data instanceof Uint8Array)) {
|
||||
throw new Error('realtime listener data must be a Uint8Array')
|
||||
}
|
||||
InternalJSApi.sendRealtime(data);
|
||||
},
|
||||
setListener: (listener) => {
|
||||
realtime_listener = listener;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
};
|
||||
})();
|
||||
|
|
Loading…
Add table
Reference in a new issue