How to send composing / is typing (Chat states) ev

2019-03-22 07:27发布

问题:

I want send composing event in Group (Multiuser) chat in xmpp, I am using asmack library, I have done same functionality with One to One chat.

I am using below code:

mMessageEventManager = new MessageEventManager(XMPPConnectApplication.getInstance().getXmppConnection());

                mMessageEventManager.addMessageEventNotificationListener(new MessageEventNotificationListener() {

                    @Override
                    public void offlineNotification(String arg0, String arg1) {

                    }

                    @Override
                    public void displayedNotification(String arg0, String arg1) {

                    }

                    @Override
                    public void deliveredNotification(String arg0, String arg1) {

                    }

                    @Override
                    public void composingNotification(String from, String to) {
                        Log.e("Receiver-composingNotification",from + " is started typing......"+to);

                    }

                    @Override
                    public void cancelledNotification(String from, String to) {
                        Log.e("Receiver-cancelledNotification",from + " is stopped typing......"+to);

                    }
                }); 

Please let me know if you have any idea for the same.

Any help will be appreciated.

回答1:

Yes, I have idea about it and I have done just before 1 week.

I have used MessageEventManager to manage Chat States.

private MessageEventManager mMessageEventManager;

Add this method for Chat State Receiving Listener:

private void chatStateRecognizer(){

        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                mMessageEventManager = new MessageEventManager(mXmppConnection);

                mMessageEventManager.addMessageEventNotificationListener(new MessageEventNotificationListener() {

                    @Override
                    public void offlineNotification(String arg0, String arg1) {

                    }

                    @Override
                    public void displayedNotification(String arg0, String arg1) {

                    }

                    @Override
                    public void deliveredNotification(String from, String arg1) {
                    }

                    @Override
                    public void composingNotification(String from, String to) {
                      Log.i("Receiver:Compose state",from + " is started typing......"+to);
                    }

                    @Override
                    public void cancelledNotification(String from, String to) {
                      Log.i("Receiver:Stop state",from + " is stopped typing......"+to);

                    }
                });
            }
        });

        thread.start();
    }

Create one Model class name with GroupInfoModel.java:

public class GroupInfoModel implements Comparable<GroupInfoModel>, Serializable{

    private static final long serialVersionUID = 1L;
    private String memberId = "", memberName = "";
    private boolean isAdmin;
    public String getMemberId() {
        return memberId;
    }
    public void setMemberId(String memberId) {
        this.memberId = memberId;
    }
    public String getMemberName() {
        return memberName;
    }
    public void setMemberName(String memberName) {
        this.memberName = memberName;
    }
    public boolean isAdmin() {
        return isAdmin;
    }
    public void setAdmin(boolean isAdmin) {
        this.isAdmin = isAdmin;
    }
    @Override
    public int compareTo(GroupInfoModel another) {
        return getMemberName().compareTo(another.getMemberName());
    }
}

Now take ArrayList of GroupInfoModel.java class:

private ArrayList<GroupInfoModel> groupDetailsList = new ArrayList<GroupInfoModel>();

private boolean isComposingStarted;

on onCreate() of Activity / Fragment:

groupDetailsList.clear();
ServiceDiscoveryManager discoManager = ServiceDiscoveryManager.getInstanceFor(mXmppConnection);
DiscoverItems items = discoManager.discoverItems(mRoomId);
    for (Iterator<Item> it = items.getItems(); it.hasNext();) {
        DiscoverItems.Item item = (DiscoverItems.Item) it.next();
        String occupant = item.getEntityID();
        occupant = occupant.split("/")[1];
        GroupInfoModel groupInfoModel = new GroupInfoModel();
        groupInfoModel.setAdmin(false);
        groupInfoModel.setMemberId(occupant+"@"+mServiceNameHere);
        groupInfoModel.setMemberName(occupant);
        groupDetailsList.add(groupInfoModel);
    }

Now add TextWatcher on your EditText of Compose Message (Chat view) screen:

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
    if(s.toString().length()==1&&!isComposingStarted){
        isComposingStarted = true;
        if(chatType.equals("OneToOneChat")){
           mMessageEventManager.sendComposingNotification(myJabberId, friendJabberId);
        }else if(chatType.equals("GroupChat")){
           for (int i = 0; i < groupDetailsList.size(); i++) {
            if(!groupDetailsList.get(i).getMemberId().contains(myJabberId)){
              mMessageEventManager.sendComposingNotification(groupDetailsList.get(i).getMemberId(), roomId);    
            }
           }
        }
    }else if(s.toString().length()==0){
        isComposingStarted = false;
        if(chatType.equals("OneToOneChat")){
            mMessageEventManager.sendCancelledNotification(myJabberId, friendJabberId);
        }else if(chatType.equals("GroupChat")){
            for (int i = 0; i < groupDetailsList.size(); i++) {
               if(!groupDetailsList.get(i).getMemberId().contains(myJabberId)){
                 mMessageEventManager.sendCancelledNotification(groupDetailsList.get(i).getMemberId(), roomId); 
               }
            }
        }
    }
}

I strongly recommended that use above code in Application class, you can modify methods as your requirements.

Done.



回答2:

// send multi user chat typing status
public static void sendMUCTypingStatus(ChatState state)
{
// check if you are connected to group
if(multiUserChat != null)
{
    try{
        // create packet
        Message statusPacket = new Message();
        // set body to null
        statusPacket.setBody(null);
        // set packet type to group chat
        statusPacket.setType(Message.Type.groupchat);
        // set subject to null
        statusPacket.setSubject(null);
        // set to the group name
        statusPacket.setTo(multiUserChat.getRoom());
        // set from my current jis example : me@domain.com
        statusPacket.setFrom(new MyPrefrence(XmppBase.context).getUsername());
        // get the chat state extension and pass our state
        ChatStateExtension extension = new ChatStateExtension(state);
        // add the extention to our packet
        statusPacket.addExtension(extension);
        // get the connection and send the packet
        Utils.getConnection().sendStanza(statusPacket);
    } catch (SmackException.NotConnectedException e) {
        e.printStackTrace();
    }
}
}

Usage :

sendMucTypingStatus(ChatState.composing);

watch this : Quick overview of using



回答3:

With RxJava and Jake Wharton's RxBinding, it's quite simple to do:

RxTextView.afterTextChangeEvents(editText)
    .observeOn(Schedulers.io())
    .skip(1)
    .map({ input ->
        // FIRE ChatState.composing EVENT HERE
        input  // just returning the argument here
    })
    .debounce(2, TimeUnit.SECONDS)
    .observeOn(Schedulers.io())
    .subscribe {
        // FIRE ChatState.active EVENT HERE
    }

Remember that we will have to write code to catch these events via smack stanzaListener and display it on the UI accordingly!

Code is written in Kotlin, but it is fairly straight forward.