~singpolyma/cheogram-android

eb8b8d63681994e7610a6f6c8502d8be0619164b — Stephen Paul Weber 4 months ago 9dc579d
Show any commands pushed along with a message
A src/cheogram/res/layout/command_button.xml => src/cheogram/res/layout/command_button.xml +8 -0
@@ 0,0 1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView
    android:id="@+id/command"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="?android:attr/buttonStyleSmall" />
</layout>

M src/main/java/eu/siacs/conversations/entities/IndividualMessage.java => src/main/java/eu/siacs/conversations/entities/IndividualMessage.java +1 -1
@@ 44,7 44,7 @@ public class IndividualMessage extends Message {
	}

	private IndividualMessage(Conversational conversation, String uuid, String conversationUUid, Jid counterpart, Jid trueCounterpart, String body, long timeSent, int encryption, int status, int type, boolean carbon, String remoteMsgId, String relativeFilePath, String serverMsgId, String fingerprint, boolean read, String edited, boolean oob, String errorMessage, Set<ReadByMarker> readByMarkers, boolean markable, boolean deleted, String bodyLanguage) {
		super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable, deleted, bodyLanguage, null, null, null);
		super(conversation, uuid, conversationUUid, counterpart, trueCounterpart, body, timeSent, encryption, status, type, carbon, remoteMsgId, relativeFilePath, serverMsgId, fingerprint, read, edited, oob, errorMessage, readByMarkers, markable, deleted, bodyLanguage, null, null, null, null);
	}

	@Override

M src/main/java/eu/siacs/conversations/entities/Message.java => src/main/java/eu/siacs/conversations/entities/Message.java +43 -4
@@ 6,6 6,7 @@ import android.graphics.Color;
import android.text.SpannableStringBuilder;
import android.util.Log;

import com.google.common.io.ByteSource;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Longs;


@@ 13,6 14,7 @@ import com.google.common.primitives.Longs;
import org.json.JSONException;

import java.lang.ref.WeakReference;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;


@@ 20,6 22,7 @@ import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.concurrent.CopyOnWriteArraySet;

import eu.siacs.conversations.Config;


@@ 35,6 38,9 @@ import eu.siacs.conversations.utils.MessageUtils;
import eu.siacs.conversations.utils.MimeUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.xml.Tag;
import eu.siacs.conversations.xml.XmlReader;

public class Message extends AbstractEntity implements AvatarService.Avatarable {



@@ 107,6 113,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
    protected boolean carbon = false;
    private boolean oob = false;
    protected URI oobUri = null;
    protected List<Element> payloads = new ArrayList<>();
    protected List<Edit> edits = new ArrayList<>();
    protected String relativeFilePath;
    protected boolean read = true;


@@ 161,6 168,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
                null,
                null,
                null,
                null,
                null);
    }



@@ 189,6 197,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
                null,
                null,
                null,
                null,
                null);
    }



@@ 198,7 207,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
                      final String remoteMsgId, final String relativeFilePath,
                      final String serverMsgId, final String fingerprint, final boolean read,
                      final String edited, final boolean oob, final String errorMessage, final Set<ReadByMarker> readByMarkers,
                      final boolean markable, final boolean deleted, final String bodyLanguage, final String subject, final String oobUri, final String fileParams) {
                      final boolean markable, final boolean deleted, final String bodyLanguage, final String subject, final String oobUri, final String fileParams, final List<Element> payloads) {
        this.conversation = conversation;
        this.uuid = uuid;
        this.conversationUuid = conversationUUid;


@@ 225,9 234,21 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
        this.bodyLanguage = bodyLanguage;
        this.subject = subject;
        if (fileParams != null) this.fileParams = new FileParams(fileParams);
    }
        if (payloads != null) this.payloads = payloads;
    }

    public static Message fromCursor(Cursor cursor, Conversation conversation) throws IOException {
        String payloadsStr = cursor.getString(cursor.getColumnIndex("payloads"));
        List<Element> payloads = new ArrayList<>();
        if (payloadsStr != null) {
            final XmlReader xmlReader = new XmlReader();
            xmlReader.setInputStream(ByteSource.wrap(payloadsStr.getBytes()).openStream());
            Tag tag;
            while ((tag = xmlReader.readTag()) != null) {
                payloads.add(xmlReader.readElement(tag));
            }
        }

    public static Message fromCursor(Cursor cursor, Conversation conversation) {
        return new Message(conversation,
                cursor.getString(cursor.getColumnIndex(UUID)),
                cursor.getString(cursor.getColumnIndex(CONVERSATION)),


@@ 253,7 274,8 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
                cursor.getString(cursor.getColumnIndex(BODY_LANGUAGE)),
                cursor.getString(cursor.getColumnIndex("subject")),
                cursor.getString(cursor.getColumnIndex("oobUri")),
                cursor.getString(cursor.getColumnIndex("fileParams"))
                cursor.getString(cursor.getColumnIndex("fileParams")),
                payloads
        );
    }



@@ 289,6 311,7 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
        values.put("subject", subject);
        values.put("oobUri", oobUri == null ? null : oobUri.toString());
        values.put("fileParams", fileParams == null ? null : fileParams.toString());
        values.put("payloads", payloads.size() < 1 ? null : payloads.stream().map(Object::toString).collect(Collectors.joining()));
        return values;
    }



@@ 841,6 864,22 @@ public class Message extends AbstractEntity implements AvatarService.Avatarable 
        this.oob = this.oobUri != null;
    }

    public void addPayload(Element el) {
        this.payloads.add(el);
    }

    public List<Element> getCommands() {
        if (this.payloads == null) return null;

        for (Element el : this.payloads) {
            if (el.getName().equals("query") && el.getNamespace().equals("http://jabber.org/protocol/disco#items") && el.getAttribute("node").equals("http://jabber.org/protocol/commands")) {
                return el.getChildren();
            }
        }

        return null;
    }

    public String getMimeType() {
        String extension;
        if (relativeFilePath != null) {

M src/main/java/eu/siacs/conversations/parser/MessageParser.java => src/main/java/eu/siacs/conversations/parser/MessageParser.java +5 -0
@@ 585,6 585,11 @@ public class MessageParser extends AbstractParser implements OnMessagePacketRece
                }
            }
            message.markable = packet.hasChild("markable", "urn:xmpp:chat-markers:0");
            for (Element el : packet.getChildren()) {
                if (el.getName().equals("query") && el.getNamespace().equals("http://jabber.org/protocol/disco#items") && el.getAttribute("node").equals("http://jabber.org/protocol/commands")) {
                    message.addPayload(el);
                }
            }
            if (conversationMultiMode) {
                message.setMucUser(conversation.getMucOptions().findUserByFullJid(counterpart));
                final Jid fallback = conversation.getMucOptions().getTrueCounterpart(counterpart);

M src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java => src/main/java/eu/siacs/conversations/persistance/DatabaseBackend.java +8 -0
@@ 244,6 244,14 @@ public class DatabaseBackend extends SQLiteOpenHelper {
                db.execSQL("PRAGMA cheogram.user_version = 2");
            }

            if(cheogramVersion < 3) {
                db.execSQL(
                    "ALTER TABLE cheogram." + Message.TABLENAME + " " +
                    "ADD COLUMN payloads TEXT"
                );
                db.execSQL("PRAGMA cheogram.user_version = 3");
            }

            db.setTransactionSuccessful();
        } finally {
            db.endTransaction();

A src/main/java/eu/siacs/conversations/ui/adapter/CommandButtonAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/CommandButtonAdapter.java +29 -0
@@ 0,0 1,29 @@
package eu.siacs.conversations.ui.adapter;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;

import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;

import eu.siacs.conversations.R;
import eu.siacs.conversations.xml.Element;
import eu.siacs.conversations.ui.XmppActivity;
import eu.siacs.conversations.databinding.CommandButtonBinding;

public class CommandButtonAdapter extends ArrayAdapter<Element> {
	public CommandButtonAdapter(XmppActivity activity) {
		super(activity, 0);
	}

	@Override
	public View getView(int position, View view, @NonNull ViewGroup parent) {
		CommandButtonBinding binding = DataBindingUtil.inflate(LayoutInflater.from(parent.getContext()), R.layout.command_button, parent, false);
		binding.command.setText(getItem(position).getAttribute("name"));
		binding.command.setFocusable(false);
		binding.command.setClickable(false);
		return binding.getRoot();
	}
}

M src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java => src/main/java/eu/siacs/conversations/ui/adapter/MessageAdapter.java +15 -0
@@ 24,6 24,7 @@ import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;


@@ 75,6 76,7 @@ import eu.siacs.conversations.utils.TimeFrameUtils;
import eu.siacs.conversations.utils.UIHelper;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.mam.MamReference;
import eu.siacs.conversations.xml.Element;

public class MessageAdapter extends ArrayAdapter<Message> {



@@ 616,6 618,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
        final boolean isInValidSession = message.isValidInSession() && (!omemoEncryption || message.isTrusted());
        final Conversational conversation = message.getConversation();
        final Account account = conversation.getAccount();
        final List<Element> commands = message.getCommands();
        final int type = getItemViewType(position);
        ViewHolder viewHolder;
        if (view == null) {


@@ 661,6 664,7 @@ public class MessageAdapter extends ArrayAdapter<Message> {
                    viewHolder.indicatorReceived = view.findViewById(R.id.indicator_received);
                    viewHolder.encryption = view.findViewById(R.id.message_encryption);
                    viewHolder.audioPlayer = view.findViewById(R.id.audio_player);
                    viewHolder.commands_list = view.findViewById(R.id.commands_list);
                    break;
                case STATUS:
                    view = activity.getLayoutInflater().inflate(R.layout.message_status, parent, false);


@@ 830,6 834,16 @@ public class MessageAdapter extends ArrayAdapter<Message> {
        }

        if (type == RECEIVED) {
            if (commands != null && conversation instanceof Conversation) {
                CommandButtonAdapter adapter = new CommandButtonAdapter(activity);
                adapter.addAll(commands);
                viewHolder.commands_list.setAdapter(adapter);
                viewHolder.commands_list.setVisibility(View.VISIBLE);
                viewHolder.commands_list.setOnItemClickListener((p, v, pos, id) -> {
                    ((Conversation) conversation).startCommand(adapter.getItem(pos), activity.xmppConnectionService);
                });
            }

            if (isInValidSession) {
                int bubble;
                if (!mUseGreenBackground) {


@@ 938,5 952,6 @@ public class MessageAdapter extends ArrayAdapter<Message> {
        protected ImageView contact_picture;
        protected TextView status_message;
        protected TextView encryption;
        protected ListView commands_list;
    }
}

M src/main/res/layout/message_content.xml => src/main/res/layout/message_content.xml +9 -1
@@ 28,6 28,14 @@
        android:longClickable="true"
        android:visibility="gone"/>

    <ListView
        android:id="@+id/commands_list"
        android:visibility="gone"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"></ListView>

    <RelativeLayout
        android:id="@+id/audio_player"
        android:layout_width="@dimen/audio_player_width"


@@ 63,4 71,4 @@
            android:progress="100"/>
    </RelativeLayout>

</merge>
\ No newline at end of file
</merge>