Search code examples
androidfirebaseandroid-adapterfirebase-realtime-databasefirebaseui

Left Right Alignment For Firebase Chat


Hi I am creating a chat application based on Firebase and Parse. In this I referred official Firebase chat example. The chat is working perfect but the incoming and sending chat both display one by one. Like this, for example

author: sender
message: hi
author: receiver
message: hi how r u?

I just need the chat to look like whats app and other chat in left and right alignment.

In firebase chat they are using two adapter one is FirebaseListAdapter (generic, which extends BaseAdapter) and other is ChatListAdapter (Which extends FirebaseCahtListAdapter). I don't know where I need to modify the code. Please help me to fix this.

FirebaseListAdapter

public abstract class FirebaseListAdapter<T> extends BaseAdapter {

private Query mRef;
private Class<T> mModelClass;
private int mLayout;
private LayoutInflater mInflater, recieveInflater;
private List<T> mModels;
private Map<String, T> mModelKeys;
private ChildEventListener mListener;


/**
 * @param mRef        The Firebase location to watch for data changes. Can also be a slice of a location, using some
 *                    combination of <code>limit()</code>, <code>startAt()</code>, and <code>endAt()</code>,
 * @param mModelClass Firebase will marshall the data at a location into an instance of a class that you provide
 * @param mLayout     This is the mLayout used to represent a single list item. You will be responsible for populating an
 *                    instance of the corresponding view with the data from an instance of mModelClass.
 * @param activity    The activity containing the ListView
 */
public FirebaseListAdapter(Query mRef, Class<T> mModelClass, int mLayout, Activity activity) {
    this.mRef = mRef;
    this.mModelClass = mModelClass;
    this.mLayout = mLayout;
    mInflater = activity.getLayoutInflater();
    mModels = new ArrayList<T>();
    mModelKeys = new HashMap<String, T>();
    // Look for all child events. We will then map them to our own internal ArrayList, which backs ListView
    mListener = this.mRef.addChildEventListener(new ChildEventListener() {
        @Override
        public void onChildAdded(DataSnapshot dataSnapshot, String previousChildName) {

            T model = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
            mModelKeys.put(dataSnapshot.getKey(), model);

            // Insert into the correct location, based on previousChildName
            if (previousChildName == null) {
                mModels.add(0, model);
            } else {
                T previousModel = mModelKeys.get(previousChildName);
                int previousIndex = mModels.indexOf(previousModel);
                int nextIndex = previousIndex + 1;
                if (nextIndex == mModels.size()) {
                    mModels.add(model);
                } else {
                    mModels.add(nextIndex, model);
                }
            }

            notifyDataSetChanged();
        }

        @Override
        public void onChildChanged(DataSnapshot dataSnapshot, String s) {

            // One of the mModels changed. Replace it in our list and name mapping
            String modelName = dataSnapshot.getKey();
            T oldModel = mModelKeys.get(modelName);
            T newModel = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
            int index = mModels.indexOf(oldModel);

            mModels.set(index, newModel);
            mModelKeys.put(modelName, newModel);

            notifyDataSetChanged();
        }

        @Override
        public void onChildRemoved(DataSnapshot dataSnapshot) {

            // A model was removed from the list. Remove it from our list and the name mapping
            String modelName = dataSnapshot.getKey();
            T oldModel = mModelKeys.get(modelName);
            mModels.remove(oldModel);
            mModelKeys.remove(modelName);
            notifyDataSetChanged();
        }

        @Override
        public void onChildMoved(DataSnapshot dataSnapshot, String previousChildName) {

            // A model changed position in the list. Update our list accordingly
            String modelName = dataSnapshot.getKey();
            T oldModel = mModelKeys.get(modelName);
            T newModel = dataSnapshot.getValue(FirebaseListAdapter.this.mModelClass);
            int index = mModels.indexOf(oldModel);
            mModels.remove(index);
            if (previousChildName == null) {
                mModels.add(0, newModel);
            } else {
                T previousModel = mModelKeys.get(previousChildName);
                int previousIndex = mModels.indexOf(previousModel);
                int nextIndex = previousIndex + 1;
                if (nextIndex == mModels.size()) {
                    mModels.add(newModel);
                } else {
                    mModels.add(nextIndex, newModel);
                }
            }
            notifyDataSetChanged();
        }

        @Override
        public void onCancelled(FirebaseError firebaseError) {
            Log.e("FirebaseListAdapter", "Listen was cancelled, no more updates will occur");
        }

    });
}

public void cleanup() {
    // We're being destroyed, let go of our mListener and forget about all of the mModels
    mRef.removeEventListener(mListener);
    mModels.clear();
    mModelKeys.clear();
}

@Override
public int getCount() {
    return mModels.size();
}

@Override
public Object getItem(int i) {
    return mModels.get(i);
}

@Override
public long getItemId(int i) {
    return i;
}

@Override
public View getView(int i, View view, ViewGroup viewGroup) {
    if (view == null) {

        view = mInflater.inflate(mLayout, viewGroup, false);

    }

    T model = mModels.get(i);

    // Call out to subclass to marshall this model into the provided view
    populateView(view, model);
    return view;
}

/**
 * Each time the data at the given Firebase location changes, this method will be called for each item that needs
 * to be displayed. The arguments correspond to the mLayout and mModelClass given to the constructor of this class.
 * <p/>
 * Your implementation should populate the view using the data contained in the model.
 *
 * @param v     The view to populate
 * @param model The object containing the data used to populate the view
 */
protected abstract void populateView(View v, T model);
}

ChatListAdapter

public class ChatListAdapter extends FirebaseListAdapter<Chat> {

// The mUsername for this client. We use this to indicate which messages originated from this user
private String mUsername;
Activity activity;
LayoutInflater inflater;

public ChatListAdapter(Query ref, Activity activity, int layout, String mUsername) {
    super(ref, Chat.class, layout, activity);
    this.mUsername = mUsername;
    this.activity = activity;
    this.inflater = (LayoutInflater) activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}

/**
 * Bind an instance of the <code>Chat</code> class to our view. This method is called by <code>FirebaseListAdapter</code>
 * when there is a data change, and we are given an instance of a View that corresponds to the layout that we passed
 * to the constructor, as well as a single <code>Chat</code> instance that represents the current data to bind.
 *
 * @param view A view instance corresponding to the layout we passed to the constructor.
 * @param chat An instance representing the current state of a chat message
 */
@Override
protected void populateView(View view, Chat chat) {

    String author = chat.getAuthor();
    TextView authorText = (TextView) view.findViewById(R.id.author);
    TextView messageText = (TextView) view.findViewById(R.id.message);

    authorText.setText(author + ": ");
    // If the message was sent by this user, design it differently
    if (author != null && author.equals(mUsername)) {
        authorText.setTextColor(view.getResources().getColor(R.color.lblFromName));
        authorText.setGravity(Gravity.RIGHT | Gravity.END);

        messageText.setText(chat.getMessage());
        messageText.setGravity(Gravity.RIGHT);
        messageText.setBackground(view.getResources().getDrawable(R.drawable.bg_msg_you));

    } else {
        authorText.setTextColor(view.getResources().getColor(R.color.lblFromName));
        authorText.setGravity(Gravity.LEFT | Gravity.START);

        messageText.setText(chat.getMessage());
        messageText.setGravity(Gravity.LEFT);
        messageText.setBackground(view.getResources().getDrawable(R.drawable.bg_msg_from));
    }

}

}

Layout File Used In CahtListAdapter

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical">

<TextView
    android:id="@+id/author"
    android:layout_width="wrap_content"
    android:text="Name"
    android:padding="5dp"
    android:textStyle="italic"
    android:textSize="12dp"
    android:layout_height="wrap_content" />

<TextView
    android:id="@+id/message"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="Content"
    android:paddingBottom="5dp"
    android:paddingLeft="10dp"
    android:paddingRight="10dp"
    android:paddingTop="5dp"
    android:textSize="16dp"
    android:layout_marginLeft="5dp"
    android:layout_marginRight="5dp"/>
</LinearLayout>

Solution

  • Finally I found a solution for this, I just added a LayoutGravity in coding, and from there I set Gravity.

    Inside ChatListAdapter

    @Override
    protected void populateView(View view, Chat chat) {
    
        String author = chat.getAuthor();
        TextView authorText = (TextView) view.findViewById(R.id.author);
        TextView messageText = (TextView) view.findViewById(R.id.message);
    
        authorText.setText(author + ": ");
        // If the message was sent by this user, design it differently
        if (author != null && author.equals(mUsername)) {
    
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.FILL_PARENT);
            params.weight = 1.0f;
            params.gravity = Gravity.RIGHT;
    
            authorText.setTextColor(view.getResources().getColor(R.color.lblFromName));
            authorText.setLayoutParams(params);
    
            messageText.setText(chat.getMessage());
            messageText.setBackground(view.getResources().getDrawable(R.drawable.bg_msg_you));
            messageText.setLayoutParams(params);
    
        } else {
            authorText.setTextColor(view.getResources().getColor(R.color.lblFromName));
            authorText.setGravity(Gravity.LEFT | Gravity.START);
    
            messageText.setText(chat.getMessage());
            messageText.setGravity(Gravity.LEFT);
            messageText.setBackground(view.getResources().getDrawable(R.drawable.bg_msg_from));
        }
    
    }