org.addhen.smssync.presentation.view.ui.fragment.MessageFragment.java Source code

Java tutorial

Introduction

Here is the source code for org.addhen.smssync.presentation.view.ui.fragment.MessageFragment.java

Source

/*
 * Copyright (c) 2010 - 2015 Ushahidi Inc
 * All rights reserved
 * Contact: team@ushahidi.com
 * Website: http://www.ushahidi.com
 * GNU Lesser General Public License Usage
 * This file may be used under the terms of the GNU Lesser
 * General Public License version 3 as published by the Free Software
 * Foundation and appearing in the file LICENSE.LGPL included in the
 * packaging of this file. Please review the following information to
 * ensure the GNU Lesser General Public License version 3 requirements
 * will be met: http://www.gnu.org/licenses/lgpl.html.
 *
 * If you have questions regarding the use of this file, please contact
 * Ushahidi developers at team@ushahidi.com.
 */

package org.addhen.smssync.presentation.view.ui.fragment;

import com.addhen.android.raiburari.presentation.ui.fragment.BaseRecyclerViewFragment;
import com.addhen.android.raiburari.presentation.ui.widget.BloatedRecyclerView;
import com.cocosw.bottomsheet.BottomSheet;
import com.nineoldandroids.view.ViewHelper;

import org.addhen.smssync.R;
import org.addhen.smssync.presentation.di.component.MessageComponent;
import org.addhen.smssync.presentation.model.MessageModel;
import org.addhen.smssync.presentation.presenter.message.DeleteMessagePresenter;
import org.addhen.smssync.presentation.presenter.message.ImportMessagePresenter;
import org.addhen.smssync.presentation.presenter.message.ListMessagePresenter;
import org.addhen.smssync.presentation.presenter.message.PublishMessagesPresenter;
import org.addhen.smssync.presentation.service.ServiceConstants;
import org.addhen.smssync.presentation.util.Utility;
import org.addhen.smssync.presentation.view.message.DeleteMessageView;
import org.addhen.smssync.presentation.view.message.ImportMessageView;
import org.addhen.smssync.presentation.view.message.ListMessageView;
import org.addhen.smssync.presentation.view.message.PublishMessageView;
import org.addhen.smssync.presentation.view.ui.activity.MainActivity;
import org.addhen.smssync.presentation.view.ui.adapter.MessageAdapter;
import org.addhen.smssync.presentation.view.ui.widget.DividerItemDecoration;

import android.annotation.TargetApi;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v4.content.ContextCompat;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.helper.ItemTouchHelper;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import javax.inject.Inject;

import butterknife.Bind;
import butterknife.ButterKnife;
import butterknife.OnClick;

/**
 * @author Ushahidi Team <team@ushahidi.com>
 */
public class MessageFragment extends BaseRecyclerViewFragment<MessageModel, MessageAdapter>
        implements ListMessageView {

    private static final int HONEYCOMB = 11;

    /** List of items pending to to be deleted **/
    public List<PendingMessage> mPendingMessages;

    @Bind(R.id.messages_fab)
    FloatingActionButton mFab;

    @Bind(R.id.messages_list)
    BloatedRecyclerView mMessageRecyclerView;

    @Inject
    ListMessagePresenter mListMessagePresenter;

    @Inject
    PublishMessagesPresenter mPublishMessagesPresenter;

    @Inject
    DeleteMessagePresenter mDeleteMessagePresenter;

    @Inject
    ImportMessagePresenter mImportMessagePresenter;

    private MessageAdapter mMessageAdapter;

    private int mRemovedItemPosition = 0;

    private MessageModel mRemovedMessage;

    private ActionMode mActionMode;

    private boolean mIsPermanentlyDeleted = true;

    public MessageFragment() {
        super(MessageAdapter.class, R.layout.fragment_list_message, R.menu.menu_messages);
    }

    public static MessageFragment newInstance() {
        return new MessageFragment();
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initialize();
    }

    @Override
    public void onResume() {
        super.onResume();
        getActivity().registerReceiver(broadcastReceiver, new IntentFilter(ServiceConstants.AUTO_SYNC_ACTION));
        mListMessagePresenter.resume();
    }

    @Override
    public void onPause() {
        super.onPause();
        getActivity().unregisterReceiver(broadcastReceiver);
        mListMessagePresenter.pause();
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        ButterKnife.unbind(this);
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mListMessagePresenter != null) {
            mListMessagePresenter.destroy();
        }
        if (mPublishMessagesPresenter != null) {
            mPublishMessagesPresenter.destroy();
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        final int id = item.getItemId();
        if (id == R.id.import_sms) {
            mImportMessagePresenter.importMessages();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    private void initialize() {
        getMessageComponent(MessageComponent.class).inject(this);
        mListMessagePresenter.setView(this);
        initializePublishPresenter();
        initializeDeletePresenter();
        initializeImportPresenter();
        initRecyclerView();
    }

    private void initializePublishPresenter() {
        mPublishMessagesPresenter.setView(new PublishMessageView() {
            @Override
            public void successfullyPublished(boolean status) {
                reloadMessages();
            }

            @Override
            public void showLoading() {
                mMessageRecyclerView.setRefreshing(true);
            }

            @Override
            public void hideLoading() {
                mMessageRecyclerView.setRefreshing(false);
            }

            @Override
            public void showRetry() {
                // Do nothing
            }

            @Override
            public void hideRetry() {
                // Do nothing
            }

            @Override
            public void showError(String s) {
                showSnackbar(mFab, s);
            }

            @Override
            public void showEnableServiceMessage(String s) {
                Snackbar snackbar = Snackbar.make(mFab, s, Snackbar.LENGTH_LONG);
                snackbar.setAction(R.string.enable, e -> {
                    ((MainActivity) getActivity()).launchIntegration();
                }).show();
            }

            @Override
            public Context getAppContext() {
                return getActivity();
            }
        });
    }

    private void initializeDeletePresenter() {
        mDeleteMessagePresenter.setView(new DeleteMessageView() {
            @Override
            public void onMessageDeleted() {
                reloadMessages();
            }

            @Override
            public void showLoading() {
                // Do nothing
            }

            @Override
            public void hideLoading() {
                // Do nothing
            }

            @Override
            public void showRetry() {
                // Do nothing
            }

            @Override
            public void hideRetry() {
                // Do nothing
            }

            @Override
            public void showError(String s) {
                showSnackbar(mFab, s);
            }

            @Override
            public Context getAppContext() {
                return getContext().getApplicationContext();
            }
        });
    }

    private void initializeImportPresenter() {
        mImportMessagePresenter.setView(new ImportMessageView() {
            @Override
            public void showMessages(List<MessageModel> messageModelList) {
                if (!Utility.isEmpty(messageModelList)) {
                    mMessageAdapter.setItems(messageModelList);
                    mFab.setVisibility(View.VISIBLE);
                    return;
                }
                mFab.setVisibility(View.GONE);
            }

            @Override
            public void showLoading() {
                mMessageRecyclerView.setRefreshing(true);
            }

            @Override
            public void hideLoading() {
                mMessageRecyclerView.setRefreshing(false);
            }

            @Override
            public void showRetry() {
                // Do nothing
            }

            @Override
            public void hideRetry() {
                // Do nothing
            }

            @Override
            public void showError(String s) {
                showSnackbar(getView(), s);
            }

            @Override
            public Context getAppContext() {
                return getContext().getApplicationContext();
            }
        });
    }

    private void initRecyclerView() {
        mPendingMessages = new ArrayList<>();
        mMessageAdapter = new MessageAdapter(getActivity());
        mMessageRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
        mMessageRecyclerView.setFocusable(true);
        mMessageRecyclerView.setFocusableInTouchMode(true);
        mMessageRecyclerView.setAdapter(mMessageAdapter);
        mMessageRecyclerView.addItemDecoration(new DividerItemDecoration(getActivity(), null));
        mMessageAdapter.setOnCheckedListener(position -> setItemChecked(position));
        mMessageRecyclerView.setItemAnimator(new DefaultItemAnimator());
        mMessageAdapter.setOnMoreActionListener(position -> new BottomSheet.Builder(getActivity())
                .sheet(R.menu.menu_messages_more_actions).listener((dialog, which) -> {
                    switch (which) {
                    case R.id.menu_messages_more_actions_delete:
                        deleteItem(position);
                        break;
                    default:
                        publishItem(position);
                    }
                }).show());
        if (Build.VERSION.SDK_INT >= HONEYCOMB) {
            enableSwipeToPerformAction();
        }
    }

    public void requestQuery(final String query) {
        Handler handler = new Handler();
        final Runnable filterDeployments = new Runnable() {
            public void run() {
                try {
                    mMessageAdapter.getFilter().filter(query);
                } catch (Exception e) {
                    reloadMessages();
                }
            }
        };

        handler.post(filterDeployments);
    }

    public void reloadMessages() {
        mListMessagePresenter.loadMessages();
    }

    private void drawSwipeListItemBackground(Canvas c, int dX, View itemView, int actionState) {
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            // Fade out the view as it is swiped out of the parent's bounds
            final float alpha = 1.0f - Math.abs(dX) / (float) itemView.getWidth();
            ViewHelper.setAlpha(itemView, alpha);
            ViewHelper.setTranslationX(itemView, dX);
            Drawable d;
            // Swiping right
            Paint p = new Paint();
            if (dX > 0) {
                d = ContextCompat.getDrawable(getAppContext(), R.drawable.swipe_right_list_item_background);
                d.setBounds(itemView.getLeft(), itemView.getTop(), dX, itemView.getBottom());
                c.drawRect((float) itemView.getLeft(), (float) itemView.getTop(), dX, (float) itemView.getBottom(),
                        p);
            } else { // Swiping left
                d = ContextCompat.getDrawable(getAppContext(), R.drawable.swipe_left_list_item_background);
                d.setBounds(itemView.getRight() + dX, itemView.getTop(), itemView.getRight(), itemView.getBottom());
                c.drawRect((float) itemView.getRight() + dX, (float) itemView.getTop(), (float) itemView.getRight(),
                        (float) itemView.getBottom(), p);
            }
            d.draw(c);
        }
    }

    private void remove(int position) {
        mRemovedItemPosition = position;
        publishItem(mRemovedItemPosition);
    }

    private void removeItems() {
        if (!Utility.isEmpty(mPendingMessages)) {
            for (PendingMessage message : mPendingMessages) {
                mMessageAdapter.removeItem(message.messageModel);
            }
        }
    }

    @TargetApi(HONEYCOMB)
    private void enableSwipeToPerformAction() {
        // Swiping doesn't work well on API 11 and below because the android support lib ships
        // with buggy APIs that makes it hard to implement on older devices.
        ItemTouchHelper.SimpleCallback swipeToDismiss = new ItemTouchHelper.SimpleCallback(0,
                ItemTouchHelper.LEFT | ItemTouchHelper.RIGHT) {
            @Override
            public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                    RecyclerView.ViewHolder target) {
                return false;
            }

            @Override
            public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
                remove(viewHolder.getAdapterPosition());
            }

            @Override
            public void onChildDraw(Canvas c, RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder,
                    float dX, float dY, int actionState, boolean isCurrentlyActive) {
                drawSwipeListItemBackground(c, (int) dX, viewHolder.itemView, actionState);
                super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive);
            }

            @Override
            public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
                super.clearView(recyclerView, viewHolder);
                ViewHelper.setAlpha(viewHolder.itemView, 1.0f);
            }

        };

        ItemTouchHelper itemTouchHelper = new ItemTouchHelper(swipeToDismiss);
        itemTouchHelper.attachToRecyclerView(mMessageRecyclerView.recyclerView);
    }

    @OnClick(R.id.messages_fab)
    void syncItems() {
        mPublishMessagesPresenter.publishMessage(mMessageAdapter.getItems());
    }

    @OnClick(android.R.id.empty)
    void importItems() {
        mImportMessagePresenter.importMessages();
    }

    @Override
    public void showMessages(List<MessageModel> messageModelList) {
        if (!Utility.isEmpty(messageModelList)) {
            mMessageAdapter.setItems(messageModelList);
            mFab.setVisibility(View.VISIBLE);
            return;
        }
        mMessageAdapter.setItems(new ArrayList<>());
        mFab.setVisibility(View.GONE);
    }

    @Override
    public void showLoading() {
        mMessageRecyclerView.setRefreshing(true);
    }

    @Override
    public void hideLoading() {
        mMessageRecyclerView.setRefreshing(false);
    }

    @Override
    public void showRetry() {
        // Do nothing
    }

    @Override
    public void hideRetry() {
        mMessageRecyclerView.setRefreshing(false);
    }

    @Override
    public void showError(String s) {
        Snackbar snackbar = Snackbar.make(mFab, s, Snackbar.LENGTH_LONG);
        View view = snackbar.getView();
        TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(getAppContext().getResources().getColor(R.color.red));
        snackbar.show();
    }

    @Override
    public Context getAppContext() {
        return getActivity().getApplicationContext();
    }

    protected <C> C getMessageComponent(Class<C> componentType) {
        return componentType.cast(((MainActivity) getActivity()).getMessageComponent());
    }

    private void showUndoSnackbar(String s) {
        Snackbar snackbar = Snackbar.make(mFab, s, Snackbar.LENGTH_LONG);
        snackbar.setAction(R.string.undo, v -> {
            // Restore item
            mMessageAdapter.addItem(mRemovedMessage, mRemovedItemPosition);
        });

        View view = snackbar.getView();
        TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(getAppContext().getResources().getColor(R.color.red));
        snackbar.setCallback(new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                super.onDismissed(snackbar, event);
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    mDeleteMessagePresenter.deleteMessage(mRemovedMessage.getMessageUuid());
                }
            }
        });
        snackbar.show();
    }

    public void setItemChecked(int position) {

        mMessageAdapter.toggleSelection(position);

        int checkedCount = mMessageAdapter.getSelectedItemCount();

        if (checkedCount == 0) {
            if (mActionMode != null) {
                mActionMode.finish();
            }
            return;
        }
        if (mActionMode == null) {
            mActionMode = ((MainActivity) getActivity()).startSupportActionMode(new ActionBarModeCallback());
        }

        if (mMessageAdapter != null) {
            mPendingMessages.add(new PendingMessage(position, mMessageAdapter.getItem(position)));

        }

        // Set the CAB title with the number of selected items
        mActionMode.setTitle(getAppContext().getString(R.string.selected, checkedCount));

    }

    /**
     * Clear all checked items in the list and the selected {@link MessageModel}
     */
    private void clearItems() {
        mMessageAdapter.clearSelections();
        if (mPendingMessages != null) {
            mPendingMessages.clear();
        }
    }

    private void deleteItems() {
        //Sort in ascending order for restoring deleted items
        Comparator cmp = Collections.reverseOrder();
        Collections.sort(mPendingMessages, cmp);
        removeItems();
        Snackbar snackbar = Snackbar.make(mFab,
                getActivity().getString(R.string.item_deleted, mPendingMessages.size()), Snackbar.LENGTH_LONG);
        snackbar.setAction(R.string.undo, e -> {
            // Restore items
            for (PendingMessage pendingDeletedDeployment : mPendingMessages) {
                mMessageAdapter.addItem(pendingDeletedDeployment.messageModel,
                        pendingDeletedDeployment.getPosition());
            }
            clearItems();
        });
        View view = snackbar.getView();
        TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(getAppContext().getResources().getColor(R.color.red));
        snackbar.setCallback(new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                super.onDismissed(snackbar, event);
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    if (mPendingMessages.size() > 0) {
                        for (PendingMessage pendingDeletedDeployment : mPendingMessages) {
                            mDeleteMessagePresenter
                                    .deleteMessage(pendingDeletedDeployment.messageModel.getMessageUuid());
                        }
                        clearItems();
                    }
                }
            }
        });
        snackbar.show();
    }

    private void publishItems() {
        //Sort in ascending order for restoring deleted items
        Comparator cmp = Collections.reverseOrder();
        Collections.sort(mPendingMessages, cmp);
        removeItems();
        Snackbar snackbar = Snackbar.make(mFab,
                getActivity().getString(R.string.item_deleted, mPendingMessages.size()), Snackbar.LENGTH_LONG);
        snackbar.setAction(R.string.undo, e -> {
            // Restore items
            for (PendingMessage pendingDeletedDeployment : mPendingMessages) {
                mMessageAdapter.addItem(pendingDeletedDeployment.messageModel,
                        pendingDeletedDeployment.getPosition());
            }
            clearItems();
        });
        View view = snackbar.getView();
        TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(getAppContext().getResources().getColor(R.color.red));
        snackbar.setCallback(new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                super.onDismissed(snackbar, event);
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    if (mPendingMessages.size() > 0) {
                        List<MessageModel> messageModels = new ArrayList<MessageModel>();
                        for (PendingMessage pendingDeletedDeployment : mPendingMessages) {
                            messageModels.add(pendingDeletedDeployment.messageModel);
                        }
                        mPublishMessagesPresenter.publishMessage(messageModels);
                        clearItems();
                    }
                }
            }
        });
        snackbar.show();
    }

    private void publishItem(int position) {
        //Sort in ascending order for restoring deleted items
        Snackbar snackbar = Snackbar.make(mFab, getActivity().getString(R.string.published), Snackbar.LENGTH_LONG);
        mRemovedMessage = mMessageAdapter.getItem(position);
        mMessageAdapter.removeItem(mRemovedMessage);
        snackbar.setAction(R.string.undo, e -> {
            // Restore items
            mMessageAdapter.addItem(mRemovedMessage, position);
        });
        View view = snackbar.getView();
        TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(getAppContext().getResources().getColor(R.color.red));
        snackbar.setCallback(new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                super.onDismissed(snackbar, event);
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    List<MessageModel> messageModels = new ArrayList<MessageModel>();
                    messageModels.add(mRemovedMessage);
                    mPublishMessagesPresenter.publishMessage(messageModels);
                }
            }
        });
        snackbar.show();
    }

    private void deleteItem(int position) {
        //Sort in ascending order for restoring deleted items
        Snackbar snackbar = Snackbar.make(mFab,
                getActivity().getString(R.string.item_deleted, mPendingMessages.size()), Snackbar.LENGTH_LONG);
        mRemovedMessage = mMessageAdapter.getItem(position);
        mMessageAdapter.removeItem(mRemovedMessage);
        snackbar.setAction(R.string.undo, e -> {
            // Restore items
            mMessageAdapter.addItem(mRemovedMessage, position);
        });
        View view = snackbar.getView();
        TextView tv = (TextView) view.findViewById(android.support.design.R.id.snackbar_text);
        tv.setTextColor(getAppContext().getResources().getColor(R.color.red));
        snackbar.setCallback(new Snackbar.Callback() {
            @Override
            public void onDismissed(Snackbar snackbar, int event) {
                super.onDismissed(snackbar, event);
                if (event != Snackbar.Callback.DISMISS_EVENT_ACTION) {
                    mDeleteMessagePresenter.deleteMessage(mRemovedMessage.getMessageUuid());
                }
            }
        });
        snackbar.show();
    }

    private static class PendingMessage implements Comparable<PendingMessage> {

        /** The message model to be deleted */
        public MessageModel messageModel;

        private int mPosition;

        public PendingMessage(int position, MessageModel messageModel) {
            mPosition = position;
            this.messageModel = messageModel;
        }

        @Override
        public int compareTo(PendingMessage other) {
            // Sort by descending position
            return other.mPosition - mPosition;
        }

        public int getPosition() {
            return mPosition;
        }
    }

    private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (intent != null) {
                mListMessagePresenter.loadMessages();
            }
        }
    };

    private class ActionBarModeCallback implements ActionMode.Callback {

        private boolean mIsActionTaken = false;

        @Override
        public boolean onCreateActionMode(ActionMode actionMode, Menu menu) {
            actionMode.getMenuInflater().inflate(R.menu.context_menu_messages, menu);
            return true;
        }

        @Override
        public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) {
            return true;
        }

        @Override
        public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) {

            if (menuItem.getItemId() == R.id.context_menu_delete) {
                deleteItems();
                mIsActionTaken = true;
            } else if (menuItem.getItemId() == R.id.context_menu_import_sms) {
                publishItems();
                mIsActionTaken = true;
            }

            if (mActionMode != null) {
                mActionMode.finish();
            }
            return mIsActionTaken;
        }

        @Override
        public void onDestroyActionMode(ActionMode actionMode) {
            if (!mIsActionTaken) {
                clearItems();
            }
            mActionMode = null;
        }
    }
}