From 2947b74b77046d3a6b92684e4211a26f992d7570 Mon Sep 17 00:00:00 2001 From: Stephen Paul Weber Date: Tue, 7 Feb 2023 21:20:25 -0500 Subject: [PATCH] Support custom actions defined by a special list-single Use the custom actions instead of the ones from when present, set the field to the value and use action=execute when tapped. --- src/cheogram/res/layout/command_page.xml | 1 + .../conversations/entities/Conversation.java | 93 +++++++++++++------ .../siacs/conversations/xmpp/forms/Data.java | 2 +- .../siacs/conversations/xmpp/forms/Field.java | 4 + .../conversations/xmpp/forms}/Option.java | 2 +- 5 files changed, 74 insertions(+), 28 deletions(-) rename src/{cheogram/java/eu/siacs/conversations/xmpp => main/java/eu/siacs/conversations/xmpp/forms}/Option.java (96%) diff --git a/src/cheogram/res/layout/command_page.xml b/src/cheogram/res/layout/command_page.xml index ba20cd29614ce5ce0b4a6d1544346357436e7562..648cc0c9b69addd58e69af40c9a5c3dfee83aa21 100644 --- a/src/cheogram/res/layout/command_page.xml +++ b/src/cheogram/res/layout/command_page.xml @@ -16,6 +16,7 @@ > { + protected Context ctx; + + public ActionsAdapter(Context ctx) { + super(ctx, R.layout.simple_list_item); + this.ctx = ctx; + } + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); + TextView tv = (TextView) v.findViewById(android.R.id.text1); + tv.setGravity(Gravity.CENTER); + tv.setText(getItem(position).second); + int resId = ctx.getResources().getIdentifier("action_" + getItem(position).first, "string" , ctx.getPackageName()); + if (resId != 0) tv.setText(ctx.getResources().getString(resId)); + tv.setTextColor(ContextCompat.getColor(ctx, R.color.white)); + tv.setBackgroundColor(UIHelper.getColorForName(getItem(position).first)); + return v; + } + + public int getPosition(String s) { + for(int i = 0; i < getCount(); i++) { + if (getItem(i).first.equals(s)) return i; + } + return -1; + } + } + final int TYPE_ERROR = 1; final int TYPE_NOTE = 2; final int TYPE_WEB = 3; @@ -2089,7 +2121,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl protected List reported = null; protected SparseArray items = new SparseArray<>(); protected XmppConnectionService xmppConnectionService; - protected ArrayAdapter actionsAdapter; + protected ActionsAdapter actionsAdapter; protected GridLayoutManager layoutManager; protected WebView actionToWebview = null; @@ -2099,19 +2131,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl mNode = node; this.xmppConnectionService = xmppConnectionService; if (mPager != null) setupLayoutManager(); - actionsAdapter = new ArrayAdapter(xmppConnectionService, R.layout.simple_list_item) { - @Override - public View getView(int position, View convertView, ViewGroup parent) { - View v = super.getView(position, convertView, parent); - TextView tv = (TextView) v.findViewById(android.R.id.text1); - tv.setGravity(Gravity.CENTER); - int resId = xmppConnectionService.getResources().getIdentifier("action_" + tv.getText() , "string" , xmppConnectionService.getPackageName()); - if (resId != 0) tv.setText(xmppConnectionService.getResources().getString(resId)); - tv.setTextColor(ContextCompat.getColor(xmppConnectionService, R.color.white)); - tv.setBackgroundColor(UIHelper.getColorForName(tv.getText().toString())); - return v; - } - }; + actionsAdapter = new ActionsAdapter(xmppConnectionService); actionsAdapter.registerDataSetObserver(new DataSetObserver() { @Override public void onChanged() { @@ -2152,11 +2172,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (!el.getNamespace().equals("http://jabber.org/protocol/commands")) continue; if (action.getName().equals("execute")) continue; - actionsAdapter.add(action.getName()); + actionsAdapter.add(Pair.create(action.getName(), action.getName())); } } if (el.getName().equals("x") && el.getNamespace().equals("jabber:x:data")) { - String title = el.findChildContent("title", "jabber:x:data"); + Data form = Data.parse(el); + String title = form.getTitle(); if (title != null) { mTitle = title; ConversationPagerAdapter.this.notifyDataSetChanged(); @@ -2167,6 +2188,15 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl setupReported(el.findChild("reported", "jabber:x:data")); if (mBinding != null) mBinding.form.setLayoutManager(setupLayoutManager()); } + + eu.siacs.conversations.xmpp.forms.Field actionList = form.getFieldByName("http://jabber.org/protocol/commands#actions"); + if (actionList != null) { + actionsAdapter.clear(); + + for (Option action : actionList.getOptions()) { + actionsAdapter.add(Pair.create(action.getValue(), action.toString())); + } + } break; } if (el.getName().equals("x") && el.getNamespace().equals("jabber:x:oob")) { @@ -2193,20 +2223,20 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (command.getAttribute("status").equals("executing") && actionsAdapter.getCount() < 1) { // No actions have been given, but we are not done? // This is probably a spec violation, but we should do *something* - actionsAdapter.add("execute"); + actionsAdapter.add(Pair.create("execute", "execute")); } if (!actionsAdapter.isEmpty()) { if (command.getAttribute("status").equals("completed") || command.getAttribute("status").equals("canceled")) { - actionsAdapter.add("close"); + actionsAdapter.add(Pair.create("close", "close")); } else if (actionsAdapter.getPosition("cancel") < 0) { - actionsAdapter.insert("cancel", 0); + actionsAdapter.insert(Pair.create("cancel", "cancel"), 0); } } } if (actionsAdapter.isEmpty()) { - actionsAdapter.add("close"); + actionsAdapter.add(Pair.create("close", "close")); } notifyDataSetChanged(); @@ -2237,6 +2267,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (el.getName().equals("field")) { String type = el.getAttribute("type"); if (type != null && type.equals("hidden")) continue; + if (el.getAttribute("var") != null && el.getAttribute("var").equals("http://jabber.org/protocol/commands#actions")) continue; } if (el.getName().equals("reported") || el.getName().equals("item")) { @@ -2270,6 +2301,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl if (el.getName().equals("field")) { String type = el.getAttribute("type"); if (type != null && type.equals("hidden")) continue; + if (el.getAttribute("var") != null && el.getAttribute("var").equals("http://jabber.org/protocol/commands#actions")) continue; } if (el.getName().equals("reported") || el.getName().equals("item")) { @@ -2407,7 +2439,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl } public boolean execute(int actionPosition) { - return execute(actionsAdapter.getItem(actionPosition)); + return execute(actionsAdapter.getItem(actionPosition).first); } public boolean execute(String action) { @@ -2429,7 +2461,6 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl final Element c = packet.addChild("command", Namespace.COMMANDS); c.setAttribute("node", mNode); c.setAttribute("sessionid", command.getAttribute("sessionid")); - c.setAttribute("action", action); String formType = responseElement == null ? null : responseElement.getAttribute("type"); if (!action.equals("cancel") && @@ -2439,6 +2470,13 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl responseElement.getNamespace().equals("jabber:x:data") && formType != null && formType.equals("form")) { + Data form = Data.parse(responseElement); + eu.siacs.conversations.xmpp.forms.Field actionList = form.getFieldByName("http://jabber.org/protocol/commands#actions"); + if (actionList != null) { + actionList.setValue(action); + c.setAttribute("action", "execute"); + } + responseElement.setAttribute("type", "submit"); Element rsm = responseElement.findChild("set", "http://jabber.org/protocol/rsm"); if (rsm != null) { @@ -2446,9 +2484,12 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl max.setContent("1000"); rsm.addChild(max); } + c.addChild(responseElement); } + if (c.getAttribute("action") == null) c.setAttribute("action", action); + xmppConnectionService.sendIqPacket(getAccount(), packet, (a, iq) -> { getView().post(() -> { updateWithResponse(iq); diff --git a/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java b/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java index 01b30a211c347b16e9b15fc75ffd125c992c2d27..a90bbd804695c2825ed0207214182caf9338f9d2 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java +++ b/src/main/java/eu/siacs/conversations/xmpp/forms/Data.java @@ -102,7 +102,7 @@ public class Data extends Element { } public String getTitle() { - return findChildContent("title"); + return findChildContent("title", "jabber:x:data"); } diff --git a/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java b/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java index f7a9eb355973330141483ff581363f3395b99279..d440dade76fedfe83a20bf49cb46858d7ac2c873 100644 --- a/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java +++ b/src/main/java/eu/siacs/conversations/xmpp/forms/Field.java @@ -65,4 +65,8 @@ public class Field extends Element { public boolean isRequired() { return hasChild("required"); } + + public List