Render result form fields

Stephen Paul Weber created

Does not handle reported/item tables yet, or fillable forms.

Change summary

src/cheogram/res/layout/command_note.xml                        |  2 
src/cheogram/res/layout/command_result_field.xml                | 32 
src/main/java/eu/siacs/conversations/entities/Conversation.java | 99 ++
3 files changed, 123 insertions(+), 10 deletions(-)

Detailed changes

src/cheogram/res/layout/command_note.xml 🔗

@@ -3,7 +3,7 @@
     xmlns:app="http://schemas.android.com/apk/res-auto">
     <LinearLayout
         android:layout_width="fill_parent"
-        android:layout_height="fill_parent"
+        android:layout_height="wrap_content"
         android:orientation="vertical">
 
         <ImageView

src/cheogram/res/layout/command_result_field.xml 🔗

@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<layout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto">
+    <LinearLayout
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:minHeight="?android:attr/listPreferredItemHeightSmall"
+            android:paddingLeft="8dp"
+            android:paddingRight="8dp"
+            android:textAppearance="@style/TextAppearance.Conversations.Body1"
+            android:textColor="?attr/edit_text_color" />
+
+        <ListView
+            android:id="@+id/values"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:layout_alignParentStart="true"
+            android:layout_alignParentLeft="true"
+            android:layout_alignParentTop="true"
+            android:background="?attr/color_background_secondary"
+            android:divider="@android:color/transparent"
+            android:dividerHeight="0dp"></ListView>
+
+    </LinearLayout>
+</layout>

src/main/java/eu/siacs/conversations/entities/Conversation.java 🔗

@@ -7,6 +7,7 @@ import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 
@@ -40,6 +41,7 @@ import eu.siacs.conversations.crypto.OmemoSetting;
 import eu.siacs.conversations.crypto.PgpDecryptionService;
 import eu.siacs.conversations.databinding.CommandPageBinding;
 import eu.siacs.conversations.databinding.CommandNoteBinding;
+import eu.siacs.conversations.databinding.CommandResultFieldBinding;
 import eu.siacs.conversations.databinding.CommandWebviewBinding;
 import eu.siacs.conversations.persistance.DatabaseBackend;
 import eu.siacs.conversations.services.AvatarService;
@@ -1300,14 +1302,14 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
                     this.binding = binding;
                 }
 
-                abstract public void bind(Element el, int position);
+                abstract public void bind(Element el);
             }
 
             class ErrorViewHolder extends ViewHolder<CommandNoteBinding> {
                 public ErrorViewHolder(CommandNoteBinding binding) { super(binding); }
 
                 @Override
-                public void bind(Element iq, int position) {
+                public void bind(Element iq) {
                     binding.errorIcon.setVisibility(View.VISIBLE);
 
                     Element error = iq.findChild("error");
@@ -1324,20 +1326,41 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
                 public NoteViewHolder(CommandNoteBinding binding) { super(binding); }
 
                 @Override
-                public void bind(Element note, int position) {
+                public void bind(Element note) {
                     binding.message.setText(note.getContent());
 
-                    if (note.getAttribute("type").equals("error")) {
+                    String type = note.getAttribute("type");
+                    if (type != null && type.equals("error")) {
                         binding.errorIcon.setVisibility(View.VISIBLE);
                     }
                 }
             }
 
+            class ResultFieldViewHolder extends ViewHolder<CommandResultFieldBinding> {
+                public ResultFieldViewHolder(CommandResultFieldBinding binding) { super(binding); }
+
+                @Override
+                public void bind(Element field) {
+                    String label = field.getAttribute("label");
+                    if (label == null) label = field.getAttribute("var");
+                    if (label == null) label = "";
+                    binding.label.setText(label);
+
+                    ArrayAdapter<String> values = new ArrayAdapter<String>(binding.getRoot().getContext(), R.layout.simple_list_item);
+                    for (Element el : field.getChildren()) {
+                        if (el.getName().equals("value") && el.getNamespace().equals("jabber:x:data")) {
+                            values.add(el.getContent());
+                        }
+                    }
+                    binding.values.setAdapter(values);
+                }
+            }
+
             class WebViewHolder extends ViewHolder<CommandWebviewBinding> {
                 public WebViewHolder(CommandWebviewBinding binding) { super(binding); }
 
                 @Override
-                public void bind(Element oob, int position) {
+                public void bind(Element oob) {
                     binding.webview.getSettings().setJavaScriptEnabled(true);
                     binding.webview.setWebViewClient(new WebViewClient() {
                         @Override
@@ -1354,6 +1377,7 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
             final int TYPE_ERROR = 1;
             final int TYPE_NOTE = 2;
             final int TYPE_WEB = 3;
+            final int TYPE_RESULT_FIELD = 4;
 
             protected String mTitle;
             protected CommandPageBinding mBinding = null;
@@ -1375,6 +1399,15 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
                 Element command = iq.findChild("command", "http://jabber.org/protocol/commands");
                 if (iq.getType() == IqPacket.TYPE.RESULT && command != null) {
                     for (Element el : command.getChildren()) {
+                        if (el.getName().equals("x") && el.getNamespace().equals("jabber:x:data")) {
+                            String title = el.findChildContent("title", "jabber:x:data");
+                            if (title != null) {
+                                mTitle = title;
+                                ConversationPagerAdapter.this.notifyDataSetChanged();
+                            }
+                            this.responseElement = el;
+                            break;
+                        }
                         if (el.getName().equals("x") && el.getNamespace().equals("jabber:x:oob")) {
                             String url = el.findChildContent("url", "jabber:x:oob");
                             if (url != null) {
@@ -1398,16 +1431,60 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
             @Override
             public int getItemCount() {
                 if (response == null) return 0;
+                if (response.getType() == IqPacket.TYPE.RESULT && responseElement.getNamespace().equals("jabber:x:data")) {
+                    int i = 0;
+                    for (Element el : responseElement.getChildren()) {
+                        if (!el.getNamespace().equals("jabber:x:data")) continue;
+                        if (el.getName().equals("title")) continue;
+                        if (el.getName().equals("field")) {
+                            String type = el.getAttribute("type");
+                            if (type != null && type.equals("hidden")) continue;
+                        }
+
+                        i++;
+                    }
+                    return i;
+                }
                 return 1;
             }
 
+            public Element getItem(int position) {
+                if (response == null) return null;
+
+                if (response.getType() == IqPacket.TYPE.RESULT) {
+                    if (responseElement.getNamespace().equals("jabber:x:data")) {
+                        int i = 0;
+                        for (Element el : responseElement.getChildren()) {
+                            if (!el.getNamespace().equals("jabber:x:data")) continue;
+                            if (el.getName().equals("title")) continue;
+                            if (el.getName().equals("field")) {
+                                String type = el.getAttribute("type");
+                                if (type != null && type.equals("hidden")) continue;
+                            }
+
+                            if (i < position) {
+                                i++;
+                                continue;
+                            }
+
+                            return el;
+                        }
+                    }
+                }
+
+                return responseElement == null ? response : responseElement;
+            }
+
             @Override
             public int getItemViewType(int position) {
                 if (response == null) return -1;
 
                 if (response.getType() == IqPacket.TYPE.RESULT) {
-                    if (responseElement.getName().equals("note")) return TYPE_NOTE;
-                    if (responseElement.getNamespace().equals("jabber:x:oob")) return TYPE_WEB;
+                    Element item = getItem(position);
+                    if (item.getName().equals("note")) return TYPE_NOTE;
+                    if (item.getNamespace().equals("jabber:x:oob")) return TYPE_WEB;
+                    if (item.getName().equals("instructions") && item.getNamespace().equals("jabber:x:data")) return TYPE_NOTE;
+                    if (item.getName().equals("field") && item.getNamespace().equals("jabber:x:data")) return TYPE_RESULT_FIELD;
                     return -1;
                 } else {
                     return TYPE_ERROR;
@@ -1429,14 +1506,18 @@ public class Conversation extends AbstractEntity implements Blockable, Comparabl
                         CommandWebviewBinding binding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()), R.layout.command_webview, container, false);
                         return new WebViewHolder(binding);
                     }
+                    case TYPE_RESULT_FIELD: {
+                        CommandResultFieldBinding binding = DataBindingUtil.inflate(LayoutInflater.from(container.getContext()), R.layout.command_result_field, container, false);
+                        return new ResultFieldViewHolder(binding);
+                    }
                     default:
-                        return null;
+                        throw new IllegalArgumentException("Unknown viewType: " + viewType);
                 }
             }
 
             @Override
             public void onBindViewHolder(ViewHolder viewHolder, int position) {
-                viewHolder.bind(responseElement == null ? response : responseElement, position);
+                viewHolder.bind(getItem(position));
             }
 
             public View getView() {