Search code examples
androidlistviewbaseadapterandroid-viewholdersendbird

Adapter-Showing view only when there is a change in a value


Below is my complete adapter class of sendbird chatting.Currently date with time is displayed with every message.viewHolder.getView("left_time") and viewHolder.getView("right_time") are views for displaying date with time and it is calculated in method getDisplayDateTime.I want date with time to be displayed only when there is a change in date.For example if there is set of messages dated 23rd june then date with time should be displayed only for the first message with date 23rd june.

I tried doing that by detecting whenever there is a change in date by storing date in xyz variable and comparing it with date of every message and whenever they are unequal then making date view of that message visible and assigning the new date to xyz variable for comparison with future messages.But this approach fails when i scroll down and scroll up list. What is the ideal approach for achieving this?

public class SendBirdMessagingAdapter extends BaseAdapter  {
    private static final int TYPE_UNSUPPORTED = 0;
    private static final int TYPE_MESSAGE = 1;
    private static final int TYPE_SYSTEM_MESSAGE = 2;
    private static final int TYPE_FILELINK = 3;
    private static final int TYPE_BROADCAST_MESSAGE = 4;
    private static final int TYPE_TYPING_INDICATOR = 5;
    private final Context mContext;
    private final LayoutInflater mInflater;
    private final ArrayList<Object> mItemList;
    private Hashtable<String, Long> mReadStatus;
    private Hashtable<String, Long> mTypeStatus;
    private List<MessagingChannel.Member> mMembers;
    private long mMaxMessageTimestamp = Long.MIN_VALUE;
    private long mMinMessageTimestamp = Long.MAX_VALUE;
    public SendBirdMessagingAdapter(Context context) {
        mContext = context;
        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        mItemList = new ArrayList<Object>();
        mReadStatus = new Hashtable<String, Long>();
        mTypeStatus = new Hashtable<String, Long>();
    }
    @Override
    public int getCount() {
        return mItemList.size() + ((mTypeStatus.size() <= 0) ? 0 : 1);
    }
    @Override
    public Object getItem(int position) {
        if (position >= mItemList.size()) {
            ArrayList<String> names = new ArrayList<String>();
            for (MessagingChannel.Member member : mMembers) {
                if (mTypeStatus.containsKey(member.getId())) {
                    names.add(member.getName());
                }
            }
            return names;
        }
        return mItemList.get(position);
    }
    public void delete(Object object) {
        mItemList.remove(object);
    }
    public void clear() {
        mMaxMessageTimestamp = Long.MIN_VALUE;
        mMinMessageTimestamp = Long.MAX_VALUE;
        mReadStatus.clear();
        mTypeStatus.clear();
        mItemList.clear();
    }
    public void resetReadStatus(Hashtable<String, Long> readStatus) {
        mReadStatus = readStatus;
    }
    public void setReadStatus(String userId, long timestamp) {
        if (mReadStatus.get(userId) == null || mReadStatus.get(userId) < timestamp) {
            mReadStatus.put(userId, timestamp);
        }
    }
    public void setTypeStatus(String userId, long timestamp) {
        if (userId.equals(SendBird.getUserId())) {
            return;
        }
        if (timestamp <= 0) {
            mTypeStatus.remove(userId);
        } else {
            mTypeStatus.put(userId, timestamp);
        }
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    public void addMessageModel(MessageModel messageModel) {
        if (messageModel.isPast()) {
            mItemList.add(0, messageModel);
        } else {
            mItemList.add(messageModel);
        }
        updateMessageTimestamp(messageModel);
    }
    private void updateMessageTimestamp(MessageModel model) {
        mMaxMessageTimestamp = mMaxMessageTimestamp < model.getTimestamp() ? model.getTimestamp() : mMaxMessageTimestamp;
        mMinMessageTimestamp = mMinMessageTimestamp > model.getTimestamp() ? model.getTimestamp() : mMinMessageTimestamp;
    }
    public long getMaxMessageTimestamp() {
        return mMaxMessageTimestamp == Long.MIN_VALUE ? Long.MAX_VALUE : mMaxMessageTimestamp;
    }
    public long getMinMessageTimestamp() {
        return mMinMessageTimestamp == Long.MAX_VALUE ? Long.MIN_VALUE : mMinMessageTimestamp;
    }
    public void setMembers(List<MessagingChannel.Member> members) {
        mMembers = members;
    }
    @Override
    public int getItemViewType(int position) {
        if (position >= mItemList.size()) {
            return TYPE_TYPING_INDICATOR;
        }
        Object item = mItemList.get(position);
        if (item instanceof Message) {
            return TYPE_MESSAGE;
        } else if (item instanceof FileLink) {
            return TYPE_FILELINK;
        } else if (item instanceof SystemMessage) {
            return TYPE_SYSTEM_MESSAGE;
        } else if (item instanceof BroadcastMessage) {
            return TYPE_BROADCAST_MESSAGE;
        }
        return TYPE_UNSUPPORTED;
    }
    @Override
    public int getViewTypeCount() {
        return 6;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder viewHolder;
        final Object item = getItem(position);
        if (convertView == null || ((ViewHolder) convertView.getTag()).getViewType() != getItemViewType(position)) {
            viewHolder = new ViewHolder();
            viewHolder.setViewType(getItemViewType(position));
            switch (getItemViewType(position)) {
                case TYPE_UNSUPPORTED:
                    convertView = new View(mInflater.getContext());
                    convertView.setTag(viewHolder);
                    break;
                case TYPE_MESSAGE: {
                    TextView tv;
                    CircularImageView iv;
                    View v;
                    convertView = mInflater.inflate(R.layout.sendbird_view_messaging_message, parent, false);
                    v = convertView.findViewById(R.id.left_container);
                    viewHolder.setView("left_container", v);
                    iv = (CircularImageView) convertView.findViewById(R.id.img_left_thumbnail);
                    viewHolder.setView("left_thumbnail", iv);
                    tv = (TextView) convertView.findViewById(R.id.txt_left);
                    viewHolder.setView("left_message", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_left_name);
                    viewHolder.setView("left_name", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_left_time);
                    viewHolder.setView("left_time", tv);
                    v = convertView.findViewById(R.id.right_container);
                    viewHolder.setView("right_container", v);
                    iv = (CircularImageView) convertView.findViewById(R.id.img_right_thumbnail);
                    viewHolder.setView("right_thumbnail", iv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right);
                    viewHolder.setView("right_message", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right_name);
                    viewHolder.setView("right_name", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right_time);
                    viewHolder.setView("right_time", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right_status);
                    viewHolder.setView("right_status", tv);
                    convertView.setTag(viewHolder);
                    break;
                }
                case TYPE_SYSTEM_MESSAGE: {
                    convertView = mInflater.inflate(R.layout.sendbird_view_system_message, parent, false);
                    viewHolder.setView("message", convertView.findViewById(R.id.txt_message));
                    convertView.setTag(viewHolder);
                    break;
                }
                case TYPE_BROADCAST_MESSAGE: {
                    convertView = mInflater.inflate(R.layout.sendbird_view_system_message, parent, false);
                    viewHolder.setView("message", convertView.findViewById(R.id.txt_message));
                    convertView.setTag(viewHolder);
                    break;
                }
                case TYPE_FILELINK: {
                    TextView tv;
                    CircularImageView civ;
                    ImageView iv;
                    View v;
                    convertView = mInflater.inflate(R.layout.sendbird_view_messaging_filelink, parent, false);
                    v = convertView.findViewById(R.id.left_container);
                    viewHolder.setView("left_container", v);
                    civ = (CircularImageView) convertView.findViewById(R.id.img_left_thumbnail);
                    viewHolder.setView("left_thumbnail", civ);
                    iv = (ImageView) convertView.findViewById(R.id.img_left);
                    viewHolder.setView("left_image", iv);
                    tv = (TextView) convertView.findViewById(R.id.txt_left_name);
                    viewHolder.setView("left_name", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_left_time);
                    viewHolder.setView("left_time", tv);
                    v = convertView.findViewById(R.id.right_container);
                    viewHolder.setView("right_container", v);
                    civ = (CircularImageView) convertView.findViewById(R.id.img_right_thumbnail);
                    viewHolder.setView("right_thumbnail", civ);
                    iv = (ImageView) convertView.findViewById(R.id.img_right);
                    viewHolder.setView("right_image", iv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right_name);
                    viewHolder.setView("right_name", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right_time);
                    viewHolder.setView("right_time", tv);
                    tv = (TextView) convertView.findViewById(R.id.txt_right_status);
                    viewHolder.setView("right_status", tv);
                    convertView.setTag(viewHolder);
                    convertView.setOnClickListener(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            new AlertDialog.Builder(mContext)
                                    .setTitle("Foodvite")
                                    .setMessage("Do you want to download this file?")
                                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            try {
                                                downloadUrl((FileLink) item, mContext);
                                            } catch (IOException e) {
                                                e.printStackTrace();
                                            }
                                        }
                                    })
                                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                        }
                                    })
                                    .create()
                                    .show();
                        }
                    });
                    break;
                }
                case TYPE_TYPING_INDICATOR: {
                    convertView = mInflater.inflate(R.layout.sendbird_view_typing_indicator, parent, false);
                    viewHolder.setView("message", convertView.findViewById(R.id.txt_message));
                    convertView.setTag(viewHolder);
                    break;
                }
            }
        }
        viewHolder = (ViewHolder) convertView.getTag();
        switch (getItemViewType(position)) {
            case TYPE_UNSUPPORTED:
                break;
            case TYPE_MESSAGE:
                Message message = (Message) item;
                if (message.getSenderId().equals(SendBird.getUserId())) {
                    viewHolder.getView("left_container", View.class).setVisibility(View.GONE);
                    viewHolder.getView("right_container", View.class).setVisibility(View.VISIBLE);
                    displayUrlImage(viewHolder.getView("right_thumbnail", CircularImageView.class), message.getSenderImageUrl(), true);
                    viewHolder.getView("right_name", TextView.class).setText(message.getSenderName());
                    viewHolder.getView("right_message", TextView.class).setText(message.getMessage());
                    viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp()));
                    int readCount = 0;
                    for (String key : mReadStatus.keySet()) {
                        if (key.equals(message.getSenderId())) {
                            readCount += 1;
                            continue;
                        }
                        if (mReadStatus.get(key) >= message.getTimestamp()) {
                            readCount += 1;
                        }
                    }
                    if (readCount < mReadStatus.size()) {
                        if (mReadStatus.size() - readCount > 1) {
                            viewHolder.getView("right_status", TextView.class).setText("Unread " + (mReadStatus.size() - readCount));
                        } else {
                            viewHolder.getView("right_status", TextView.class).setText("Unread");
                        }
                    } else {
                        viewHolder.getView("right_status", TextView.class).setText("");
                    }
                    viewHolder.getView("right_container").setOnLongClickListener(new View.OnLongClickListener() {
                        @Override
                        public boolean onLongClick(View v) {
                            new AlertDialog.Builder(mContext)
                                    .setTitle("Foodvite")
                                    .setMessage("Do you want to delete a message?")
                                    .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                            SendBird.deleteMessage(((Message) item).getMessageId(), new DeleteMessageHandler() {
                                                @Override
                                                public void onError(SendBirdException e) {
                                                    e.printStackTrace();
                                                }
                                                @Override
                                                public void onSuccess(long messageId) {
                                                    mSendBirdMessagingAdapter.delete(item);
                                                    mSendBirdMessagingAdapter.notifyDataSetChanged();
                                                    Toast.makeText(mContext, "Message has been deleted.", Toast.LENGTH_SHORT).show();
                                                }
                                            });
                                        }
                                    })
                                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                                        @Override
                                        public void onClick(DialogInterface dialog, int which) {
                                        }
                                    })
                                    .create()
                                    .show();
                            return true;
                        }
                    });
                } else {
                    viewHolder.getView("left_container", View.class).setVisibility(View.VISIBLE);
                    viewHolder.getView("right_container", View.class).setVisibility(View.GONE);
                    displayUrlImage(viewHolder.getView("left_thumbnail", CircularImageView.class), message.getSenderImageUrl(), true);
                    viewHolder.getView("left_name", TextView.class).setText(message.getSenderName());
                    viewHolder.getView("left_message", TextView.class).setText(message.getMessage());
                    viewHolder.getView("left_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp()));
                    if(isGroupChat)
                        viewHolder.getView("left_name", TextView.class).setVisibility(View.VISIBLE);
                    else
                        viewHolder.getView("left_name", TextView.class).setVisibility(View.GONE);
                }
                break;
            case TYPE_SYSTEM_MESSAGE:
                SystemMessage systemMessage = (SystemMessage) item;
                viewHolder.getView("message", TextView.class).setText(Html.fromHtml(systemMessage.getMessage()));
                break;
            case TYPE_BROADCAST_MESSAGE:
                BroadcastMessage broadcastMessage = (BroadcastMessage) item;
                viewHolder.getView("message", TextView.class).setText(Html.fromHtml(broadcastMessage.getMessage()));
                break;
            case TYPE_FILELINK:
                FileLink fileLink = (FileLink) item;
                if (fileLink.getSenderId().equals(SendBird.getUserId())) {
                    viewHolder.getView("left_container", View.class).setVisibility(View.GONE);
                    viewHolder.getView("right_container", View.class).setVisibility(View.VISIBLE);
                    displayUrlImage(viewHolder.getView("right_thumbnail", ImageView.class), fileLink.getSenderImageUrl(), true);
                    viewHolder.getView("right_name", TextView.class).setText(fileLink.getSenderName());
                    if (fileLink.getFileInfo().getType().toLowerCase().startsWith("image")) {
                        displayUrlImage(viewHolder.getView("right_image", ImageView.class), fileLink.getFileInfo().getUrl());
                    } else {
                        viewHolder.getView("right_image", CircularImageView.class).setImageResource(R.drawable.sendbird_icon_file);
                    }
                    viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, fileLink.getTimestamp()));
                    int readCount = 0;
                    for (String key : mReadStatus.keySet()) {
                        if (key.equals(fileLink.getSenderId())) {
                            continue;
                        }
                        if (mReadStatus.get(key) < fileLink.getTimestamp()) {
                            readCount += 1;
                        }
                    }
                    if (readCount < mReadStatus.size() - 1) {
                        viewHolder.getView("right_status", TextView.class).setText("Unread");
                    } else {
                        viewHolder.getView("right_status", TextView.class).setText("");
                    }
                } else {
                    viewHolder.getView("left_container", View.class).setVisibility(View.VISIBLE);
                    viewHolder.getView("right_container", View.class).setVisibility(View.GONE);
                    displayUrlImage(viewHolder.getView("left_thumbnail", ImageView.class), fileLink.getSenderImageUrl(), true);
                    viewHolder.getView("left_name", TextView.class).setText(fileLink.getSenderName());
                    if (fileLink.getFileInfo().getType().toLowerCase().startsWith("image")) {
                        displayUrlImage(viewHolder.getView("left_image", ImageView.class), fileLink.getFileInfo().getUrl());
                    } else {
                        viewHolder.getView("left_image", CircularImageView.class).setImageResource(R.drawable.sendbird_icon_file);
                    }
                    if(isGroupChat)
                        viewHolder.getView("left_name", TextView.class).setVisibility(View.VISIBLE);
                    else
                        viewHolder.getView("left_name", TextView.class).setVisibility(View.GONE);
                    viewHolder.getView("left_time", TextView.class).setText(getDisplayDateTime(mContext, fileLink.getTimestamp()));
                }
                break;
            case TYPE_TYPING_INDICATOR: {
                int itemCount = ((List) item).size();
                String typeMsg = ((List) item).get(0)
                        + ((itemCount > 1) ? " +" + (itemCount - 1) : "")
                        + ((itemCount > 1) ? " are " : " is ")
                        + "typing...";
                viewHolder.getView("message", TextView.class).setText(typeMsg);
                break;
            }
        }
        return convertView;
    }
    public boolean checkTypeStatus() {
        /**
         * Clear an old type status.
         */
        for (String key : mTypeStatus.keySet()) {
            Long ts = mTypeStatus.get(key);
            if (System.currentTimeMillis() - ts > 10 * 1000L) {
                mTypeStatus.remove(key);
                return true;
            }
        }
        return false;
    }
    private class ViewHolder {
        private Hashtable<String, View> holder = new Hashtable<String, View>();
        private int type;
        public int getViewType() {
            return this.type;
        }
        public void setViewType(int type) {
            this.type = type;
        }
        public void setView(String k, View v) {
            holder.put(k, v);
        }
        public View getView(String k) {
            return holder.get(k);
        }
        public <T> T getView(String k, Class<T> type) {
            return type.cast(getView(k));
        }
    }
}
private static String getDisplayDateTime(Context context, long milli) {
    Date date = new Date(milli);
    if (System.currentTimeMillis() - milli < 60 * 60 * 24 * 1000l) {
        return DateFormat.getTimeFormat(context).format(date);
    }
    return DateFormat.getDateFormat(context).format(date) + " " + DateFormat.getTimeFormat(context).format(date);
}

Solution

  • Try below code for your method,

      private static String getDisplayDateTime(Context context, long milli, long milli2) 
      {
          Date date = new Date(milli);
          Date previousDate = new Date(milli2);
          String strCurrentDate = "", strPreviousDate = "";
    
         if (System.currentTimeMillis() - milli < 60 * 60 * 24 * 1000l) 
         {
            strCurrentDate = DateFormat.getTimeFormat(context).format(date);
    
            if(milli2 != -1)
                strPreviousDate = DateFormat.getTimeFormat(context).format(previousDate);
            //return strCurrentDate.equals(strPreviousDate) ? "" : strCurrentDate;
         }
         else
         {
           strCurrentDate = DateFormat.getDateFormat(context).format(date) + " " + DateFormat.getTimeFormat(context).format(date);
    
            if(milli2 != -1)
                 strPreviousDate = DateFormat.getDateFormat(context).format(strPreviousDate) + " " + DateFormat.getTimeFormat(context).format(strPreviousDate);
         }
        return strCurrentDate.equals(strPreviousDate) ? "" : strCurrentDate;
     }
    

    Now call your methods like below

       if(position > 0)
        {
           final Object previousItem = getItem(position - 1);
           Message previousMessage = (Message) previousItem;
    
           viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp(), previousMessage.getTimestamp()));
        }
        else
        {
           viewHolder.getView("right_time", TextView.class).setText(getDisplayDateTime(mContext, message.getTimestamp(), -1));
        }