| package org.wordpress.android.ui.comments; |
| |
| import android.app.AlertDialog; |
| import android.app.Fragment; |
| import android.content.DialogInterface; |
| import android.graphics.drawable.Drawable; |
| import android.os.AsyncTask; |
| import android.os.Bundle; |
| import android.support.v4.content.ContextCompat; |
| import android.support.v7.app.AppCompatActivity; |
| import android.support.v7.view.ActionMode; |
| import android.view.LayoutInflater; |
| import android.view.Menu; |
| import android.view.MenuInflater; |
| import android.view.MenuItem; |
| import android.view.View; |
| import android.view.ViewGroup; |
| |
| import org.wordpress.android.R; |
| import org.wordpress.android.WordPress; |
| import org.wordpress.android.datasets.CommentTable; |
| import org.wordpress.android.models.Blog; |
| import org.wordpress.android.models.Comment; |
| import org.wordpress.android.models.CommentList; |
| import org.wordpress.android.models.CommentStatus; |
| import org.wordpress.android.models.FilterCriteria; |
| import org.wordpress.android.ui.EmptyViewMessageType; |
| import org.wordpress.android.ui.FilteredRecyclerView; |
| import org.wordpress.android.ui.prefs.AppPrefs; |
| import org.wordpress.android.util.AppLog; |
| import org.wordpress.android.util.NetworkUtils; |
| import org.wordpress.android.util.ToastUtils; |
| import org.xmlrpc.android.ApiHelper; |
| import org.xmlrpc.android.ApiHelper.ErrorType; |
| import org.xmlrpc.android.XMLRPCFault; |
| |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import de.greenrobot.event.EventBus; |
| |
| public class CommentsListFragment extends Fragment implements CommentAdapter.OnDataLoadedListener, |
| CommentAdapter.OnLoadMoreListener, CommentAdapter.OnSelectedItemsChangeListener, CommentAdapter.OnCommentPressedListener { |
| |
| interface OnCommentSelectedListener { |
| void onCommentSelected(long commentId); |
| } |
| |
| private boolean mIsUpdatingComments = false; |
| private boolean mCanLoadMoreComments = true; |
| boolean mHasAutoRefreshedComments = false; |
| |
| private final CommentStatus[] commentStatuses = {CommentStatus.UNKNOWN, CommentStatus.UNAPPROVED, |
| CommentStatus.APPROVED, CommentStatus.TRASH, CommentStatus.SPAM}; |
| |
| private EmptyViewMessageType mEmptyViewMessageType = EmptyViewMessageType.NO_CONTENT; |
| private FilteredRecyclerView mFilteredCommentsView; |
| private CommentAdapter mAdapter; |
| private ActionMode mActionMode; |
| private CommentStatus mCommentStatusFilter; |
| |
| private UpdateCommentsTask mUpdateCommentsTask; |
| |
| public static final int COMMENTS_PER_PAGE = 30; |
| |
| private CommentAdapterState mCommentAdapterState; |
| |
| |
| private boolean hasAdapter() { |
| return (mAdapter != null); |
| } |
| |
| private int getSelectedCommentCount() { |
| return getAdapter().getSelectedCommentCount(); |
| } |
| |
| public void removeComment(Comment comment) { |
| if (hasAdapter() && comment != null) { |
| getAdapter().removeComment(comment); |
| } |
| } |
| |
| @Override |
| public void onActivityCreated(Bundle savedInstanceState) { |
| super.onActivityCreated(savedInstanceState); |
| |
| Bundle extras = getActivity().getIntent().getExtras(); |
| if (extras != null) { |
| mHasAutoRefreshedComments = extras.getBoolean(CommentsActivity.KEY_AUTO_REFRESHED); |
| mEmptyViewMessageType = EmptyViewMessageType.getEnumFromString(extras.getString( |
| CommentsActivity.KEY_EMPTY_VIEW_MESSAGE)); |
| } else { |
| mHasAutoRefreshedComments = false; |
| mEmptyViewMessageType = EmptyViewMessageType.NO_CONTENT; |
| } |
| |
| if (savedInstanceState != null) { |
| mCommentAdapterState = savedInstanceState.getParcelable(CommentAdapterState.KEY); |
| } |
| |
| if (!NetworkUtils.isNetworkAvailable(getActivity())) { |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.NETWORK_ERROR); |
| return; |
| } |
| |
| // Restore the empty view's message |
| mFilteredCommentsView.updateEmptyView(mEmptyViewMessageType); |
| |
| if (!mHasAutoRefreshedComments) { |
| updateComments(false); |
| mFilteredCommentsView.setRefreshing(true); |
| mHasAutoRefreshedComments = true; |
| } |
| } |
| |
| @Override |
| public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { |
| View view = inflater.inflate(R.layout.comment_list_fragment, container, false); |
| |
| mFilteredCommentsView = (FilteredRecyclerView) view.findViewById(R.id.filtered_recycler_view); |
| mFilteredCommentsView.setLogT(AppLog.T.COMMENTS); |
| mFilteredCommentsView.setFilterListener(new FilteredRecyclerView.FilterListener() { |
| @Override |
| public List<FilterCriteria> onLoadFilterCriteriaOptions(boolean refresh) { |
| @SuppressWarnings("unchecked") |
| ArrayList<FilterCriteria> criteria = new ArrayList(); |
| Collections.addAll(criteria, commentStatuses); |
| return criteria; |
| } |
| |
| @Override |
| public void onLoadFilterCriteriaOptionsAsync(FilteredRecyclerView.FilterCriteriaAsyncLoaderListener listener, boolean refresh) { |
| } |
| |
| @Override |
| public void onLoadData() { |
| updateComments(false); |
| } |
| |
| @Override |
| public void onFilterSelected(int position, FilterCriteria criteria) { |
| //trackCommentsAnalytics(); |
| AppPrefs.setCommentsStatusFilter((CommentStatus) criteria); |
| mCommentStatusFilter = (CommentStatus) criteria; |
| finishActionMode(); |
| } |
| |
| @Override |
| public FilterCriteria onRecallSelection() { |
| mCommentStatusFilter = AppPrefs.getCommentsStatusFilter(); |
| return mCommentStatusFilter; |
| } |
| |
| @Override |
| public String onShowEmptyViewMessage(EmptyViewMessageType emptyViewMsgType) { |
| |
| if (emptyViewMsgType == EmptyViewMessageType.NO_CONTENT) { |
| FilterCriteria filter = mFilteredCommentsView.getCurrentFilter(); |
| if (filter == null || CommentStatus.UNKNOWN.equals(filter)) { |
| return getString(R.string.comments_empty_list); |
| } else { |
| switch (mCommentStatusFilter) { |
| case APPROVED: |
| return getString(R.string.comments_empty_list_filtered_approved); |
| case UNAPPROVED: |
| return getString(R.string.comments_empty_list_filtered_pending); |
| case SPAM: |
| return getString(R.string.comments_empty_list_filtered_spam); |
| case TRASH: |
| return getString(R.string.comments_empty_list_filtered_trashed); |
| default: |
| return getString(R.string.comments_empty_list); |
| } |
| } |
| |
| } else { |
| int stringId = 0; |
| switch (emptyViewMsgType) { |
| case LOADING: |
| stringId = R.string.comments_fetching; |
| break; |
| case NETWORK_ERROR: |
| stringId = R.string.no_network_message; |
| break; |
| case PERMISSION_ERROR: |
| stringId = R.string.error_refresh_unauthorized_comments; |
| break; |
| case GENERIC_ERROR: |
| stringId = R.string.error_refresh_comments; |
| break; |
| } |
| return getString(stringId); |
| } |
| |
| } |
| |
| @Override |
| public void onShowCustomEmptyView(EmptyViewMessageType emptyViewMsgType) { |
| } |
| }); |
| |
| // the following will change the look and feel of the toolbar to match the current design |
| mFilteredCommentsView.setToolbarBackgroundColor(ContextCompat.getColor(getActivity(), R.color.blue_medium)); |
| mFilteredCommentsView.setToolbarSpinnerTextColor(ContextCompat.getColor(getActivity(), R.color.white)); |
| mFilteredCommentsView.setToolbarSpinnerDrawable(R.drawable.arrow); |
| mFilteredCommentsView.setToolbarLeftAndRightPadding( |
| getResources().getDimensionPixelSize(R.dimen.margin_filter_spinner), |
| getResources().getDimensionPixelSize(R.dimen.margin_none)); |
| |
| return view; |
| } |
| |
| @Override |
| public void onResume() { |
| super.onResume(); |
| if (mFilteredCommentsView.getAdapter() == null) { |
| mFilteredCommentsView.setAdapter(getAdapter()); |
| if (!NetworkUtils.isNetworkAvailable(getActivity())) { |
| ToastUtils.showToast(getActivity(), getString(R.string.error_refresh_comments_showing_older)); |
| } |
| getAdapter().loadComments(mCommentStatusFilter); |
| } |
| } |
| |
| public void setCommentStatusFilter(CommentStatus statusFilter) { |
| mCommentStatusFilter = statusFilter; |
| } |
| |
| private void moderateSelectedComments(final CommentStatus newStatus) { |
| if (!NetworkUtils.checkConnection(getActivity())) return; |
| |
| final CommentList selectedComments = getAdapter().getSelectedComments(); |
| final CommentList updateComments = new CommentList(); |
| |
| // build list of comments whose status is different than passed |
| for (Comment comment : selectedComments) { |
| if (comment.getStatusEnum() != newStatus) { |
| setCommentIsModerating(comment.commentID, true); |
| updateComments.add(comment); |
| } |
| |
| } |
| if (updateComments.size() == 0) return; |
| |
| CommentActions.OnCommentsModeratedListener listener = new CommentActions.OnCommentsModeratedListener() { |
| @Override |
| public void onCommentsModerated(final CommentList moderatedComments) { |
| EventBus.getDefault().post( |
| new CommentEvents.CommentsBatchModerationFinishedEvent(moderatedComments, false)); |
| } |
| }; |
| |
| getAdapter().clearSelectedComments(); |
| finishActionMode(); |
| |
| CommentActions.moderateComments( |
| WordPress.getCurrentLocalTableBlogId(), |
| updateComments, |
| newStatus, |
| listener); |
| } |
| |
| |
| private void confirmDeleteComments() { |
| if (CommentStatus.TRASH.equals(mCommentStatusFilter)) { |
| AlertDialog.Builder dialogBuilder = new AlertDialog.Builder( |
| getActivity()); |
| dialogBuilder.setTitle(getResources().getText(R.string.delete)); |
| int resId = getAdapter().getSelectedCommentCount() > 1 ? R.string.dlg_sure_to_delete_comments : R.string.dlg_sure_to_delete_comment; |
| dialogBuilder.setMessage(getResources().getText(resId)); |
| dialogBuilder.setPositiveButton(getResources().getText(R.string.yes), |
| new DialogInterface.OnClickListener() { |
| public void onClick(DialogInterface dialog, int whichButton) { |
| deleteSelectedComments(true); |
| } |
| }); |
| dialogBuilder.setNegativeButton( |
| getResources().getText(R.string.no), |
| null); |
| dialogBuilder.setCancelable(true); |
| dialogBuilder.create().show(); |
| |
| } else { |
| |
| AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); |
| builder.setMessage(R.string.dlg_confirm_trash_comments); |
| builder.setTitle(R.string.trash); |
| builder.setCancelable(true); |
| builder.setPositiveButton(R.string.trash_yes, new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog, int id) { |
| deleteSelectedComments(false); |
| } |
| }); |
| builder.setNegativeButton(R.string.trash_no, new DialogInterface.OnClickListener() { |
| @Override |
| public void onClick(DialogInterface dialog, int id) { |
| dialog.cancel(); |
| } |
| }); |
| AlertDialog alert = builder.create(); |
| alert.show(); |
| } |
| } |
| |
| private void deleteSelectedComments(boolean deletePermanently) { |
| if (!NetworkUtils.checkConnection(getActivity())) return; |
| |
| |
| final CommentList selectedComments = getAdapter().getSelectedComments(); |
| |
| for (Comment comment : selectedComments) { |
| setCommentIsModerating(comment.commentID, true); |
| } |
| |
| final CommentStatus newStatus = deletePermanently ? CommentStatus.DELETE : CommentStatus.TRASH; |
| |
| |
| CommentActions.OnCommentsModeratedListener listener = new CommentActions.OnCommentsModeratedListener() { |
| @Override |
| public void onCommentsModerated(final CommentList deletedComments) { |
| EventBus.getDefault().post( |
| new CommentEvents.CommentsBatchModerationFinishedEvent(deletedComments, true)); |
| } |
| }; |
| |
| getAdapter().clearSelectedComments(); |
| CommentActions.moderateComments( |
| WordPress.getCurrentLocalTableBlogId(), selectedComments, newStatus, listener); |
| } |
| |
| void loadComments() { |
| // this is called from CommentsActivity when a comment was changed in the detail view, |
| // and the change will already be in SQLite so simply reload the comment adapter |
| // to show the change |
| getAdapter().loadComments(mCommentStatusFilter); |
| } |
| |
| void updateEmptyView() { |
| //this is called from CommentsActivity in the case the last moment for a given type has been changed from that |
| //status, leaving the list empty, so we need to update the empty view. The method inside FilteredRecyclerView |
| //does the handling itself, so we only check for null here. |
| if (mFilteredCommentsView != null) { |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.NO_CONTENT); |
| } |
| } |
| |
| /* |
| * get latest comments from server, or pass loadMore=true to get comments beyond the |
| * existing ones |
| */ |
| void updateComments(boolean loadMore) { |
| if (mIsUpdatingComments) { |
| AppLog.w(AppLog.T.COMMENTS, "update comments task already running"); |
| return; |
| } else if (!NetworkUtils.isNetworkAvailable(getActivity())) { |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.NETWORK_ERROR); |
| mFilteredCommentsView.setRefreshing(false); |
| ToastUtils.showToast(getActivity(), getString(R.string.error_refresh_comments_showing_older)); |
| //we're offline, load/refresh whatever we have in our local db |
| getAdapter().loadComments(mCommentStatusFilter); |
| return; |
| } |
| |
| //immediately load/refresh whatever we have in our local db as we wait for the API call to get latest results |
| if (!loadMore) { |
| getAdapter().loadComments(mCommentStatusFilter); |
| } |
| |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.LOADING); |
| |
| mUpdateCommentsTask = new UpdateCommentsTask(loadMore, mCommentStatusFilter); |
| mUpdateCommentsTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); |
| } |
| |
| public void setCommentIsModerating(long commentId, boolean isModerating) { |
| if (!hasAdapter()) return; |
| |
| if (isModerating) { |
| getAdapter().addModeratingCommentId(commentId); |
| } else { |
| getAdapter().removeModeratingCommentId(commentId); |
| } |
| } |
| |
| public String getEmptyViewMessage() { |
| return mEmptyViewMessageType.name(); |
| } |
| |
| /* |
| * task to retrieve latest comments from server |
| */ |
| private class UpdateCommentsTask extends AsyncTask<Void, Void, CommentList> { |
| ErrorType mErrorType = ErrorType.NO_ERROR; |
| final boolean mIsLoadingMore; |
| final CommentStatus mStatusFilter; |
| |
| private UpdateCommentsTask(boolean loadMore, CommentStatus statusFilter) { |
| mIsLoadingMore = loadMore; |
| mStatusFilter = statusFilter; |
| } |
| |
| @Override |
| protected void onPreExecute() { |
| super.onPreExecute(); |
| mIsUpdatingComments = true; |
| if (mIsLoadingMore) { |
| mFilteredCommentsView.showLoadingProgress(); |
| } |
| } |
| |
| @Override |
| protected void onCancelled() { |
| super.onCancelled(); |
| mIsUpdatingComments = false; |
| mUpdateCommentsTask = null; |
| mFilteredCommentsView.setRefreshing(false); |
| } |
| |
| @Override |
| protected CommentList doInBackground(Void... args) { |
| if (!isAdded()) { |
| return null; |
| } |
| |
| final Blog blog = WordPress.getCurrentBlog(); |
| if (blog == null) { |
| mErrorType = ErrorType.INVALID_CURRENT_BLOG; |
| return null; |
| } |
| |
| Map<String, Object> hPost = new HashMap<>(); |
| if (mIsLoadingMore) { |
| int numExisting = getAdapter().getItemCount(); |
| hPost.put("offset", numExisting); |
| hPost.put("number", COMMENTS_PER_PAGE); |
| } else { |
| hPost.put("number", COMMENTS_PER_PAGE); |
| } |
| |
| if (mStatusFilter != null) { |
| //if this is UNKNOWN that means show ALL, i.e., do not apply filter |
| if (!mStatusFilter.equals(CommentStatus.UNKNOWN)) { |
| hPost.put("status", CommentStatus.toString(mStatusFilter)); |
| } |
| } |
| |
| Object[] params = {blog.getRemoteBlogId(), |
| blog.getUsername(), |
| blog.getPassword(), |
| hPost}; |
| try { |
| return ApiHelper.refreshComments(blog, params, new ApiHelper.DatabasePersistCallback() { |
| @Override |
| public void onDataReadyToSave(List list) { |
| int localBlogId = blog.getLocalTableBlogId(); |
| |
| if (!mIsLoadingMore) { //existing comments should be deleted only if we are not "loading more" |
| CommentTable.deleteCommentsForBlogWithFilter(localBlogId, mStatusFilter); |
| } |
| CommentTable.saveComments(localBlogId, (CommentList) list); |
| } |
| }); |
| } catch (XMLRPCFault xmlrpcFault) { |
| mErrorType = ErrorType.UNKNOWN_ERROR; |
| if (xmlrpcFault.getFaultCode() == 401) { |
| mErrorType = ErrorType.UNAUTHORIZED; |
| } |
| } catch (Exception e) { |
| mErrorType = ErrorType.UNKNOWN_ERROR; |
| } |
| return null; |
| } |
| |
| protected void onPostExecute(CommentList comments) { |
| |
| boolean isRefreshing = mFilteredCommentsView.isRefreshing(); |
| mIsUpdatingComments = false; |
| mUpdateCommentsTask = null; |
| |
| if (!isAdded()) return; |
| |
| if (mIsLoadingMore) { |
| mFilteredCommentsView.hideLoadingProgress(); |
| } |
| mFilteredCommentsView.setRefreshing(false); |
| |
| if (isCancelled()) return; |
| |
| mCanLoadMoreComments = (comments != null && comments.size() > 0); |
| |
| // result will be null on error OR if no more comments exists |
| if (comments == null && !getActivity().isFinishing() && mErrorType != ErrorType.NO_ERROR) { |
| switch (mErrorType) { |
| case UNAUTHORIZED: |
| if (!mFilteredCommentsView.emptyViewIsVisible()) { |
| ToastUtils.showToast(getActivity(), getString(R.string.error_refresh_unauthorized_comments)); |
| } |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.PERMISSION_ERROR); |
| return; |
| default: |
| ToastUtils.showToast(getActivity(), getString(R.string.error_refresh_comments)); |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.GENERIC_ERROR); |
| return; |
| } |
| } |
| |
| if (!getActivity().isFinishing()) { |
| if (comments != null && comments.size() > 0) { |
| getAdapter().loadComments(mStatusFilter); |
| } else { |
| if (isRefreshing) { |
| //if refreshing and no errors, we only want freshest stuff, so clear old data |
| getAdapter().clearComments(); |
| } |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.NO_CONTENT); |
| } |
| } |
| } |
| } |
| |
| @Override |
| public void onSaveInstanceState(Bundle outState) { |
| if (outState.isEmpty()) { |
| outState.putBoolean("bug_19917_fix", true); |
| } |
| |
| if (hasAdapter()) { |
| outState.putParcelable(CommentAdapterState.KEY, getAdapter().getAdapterState()); |
| } |
| |
| super.onSaveInstanceState(outState); |
| } |
| |
| /**** |
| * Contextual ActionBar (CAB) routines |
| ***/ |
| private void updateActionModeTitle() { |
| if (mActionMode == null) |
| return; |
| int numSelected = getSelectedCommentCount(); |
| if (numSelected > 0) { |
| mActionMode.setTitle(Integer.toString(numSelected)); |
| } else { |
| mActionMode.setTitle(""); |
| } |
| } |
| |
| private void finishActionMode() { |
| if (mActionMode != null) { |
| mActionMode.finish(); |
| } |
| } |
| |
| private final class ActionModeCallback implements ActionMode.Callback { |
| @Override |
| public boolean onCreateActionMode(ActionMode actionMode, Menu menu) { |
| mActionMode = actionMode; |
| MenuInflater inflater = actionMode.getMenuInflater(); |
| inflater.inflate(R.menu.menu_comments_cab, menu); |
| mFilteredCommentsView.setSwipeToRefreshEnabled(false); |
| return true; |
| } |
| |
| private void setItemEnabled(Menu menu, int menuId, boolean isEnabled) { |
| final MenuItem item = menu.findItem(menuId); |
| if (item == null || item.isEnabled() == isEnabled) |
| return; |
| item.setEnabled(isEnabled); |
| if (item.getIcon() != null) { |
| // must mutate the drawable to avoid affecting other instances of it |
| Drawable icon = item.getIcon().mutate(); |
| icon.setAlpha(isEnabled ? 255 : 128); |
| item.setIcon(icon); |
| } |
| } |
| |
| @Override |
| public boolean onPrepareActionMode(ActionMode actionMode, Menu menu) { |
| final CommentList selectedComments = getAdapter().getSelectedComments(); |
| |
| boolean hasSelection = (selectedComments.size() > 0); |
| boolean hasApproved = hasSelection && selectedComments.hasAnyWithStatus(CommentStatus.APPROVED); |
| boolean hasUnapproved = hasSelection && selectedComments.hasAnyWithStatus(CommentStatus.UNAPPROVED); |
| boolean hasSpam = hasSelection && selectedComments.hasAnyWithStatus(CommentStatus.SPAM); |
| boolean hasAnyNonSpam = hasSelection && selectedComments.hasAnyWithoutStatus(CommentStatus.SPAM); |
| boolean hasTrash = hasSelection && selectedComments.hasAnyWithStatus(CommentStatus.TRASH); |
| |
| setItemEnabled(menu, R.id.menu_approve, hasUnapproved || hasSpam || hasTrash); |
| setItemEnabled(menu, R.id.menu_unapprove, hasApproved); |
| setItemEnabled(menu, R.id.menu_spam, hasAnyNonSpam); |
| setItemEnabled(menu, R.id.menu_trash, hasSelection); |
| |
| final MenuItem trashItem = menu.findItem(R.id.menu_trash); |
| if (trashItem != null) { |
| if (CommentStatus.TRASH.equals(mCommentStatusFilter)) { |
| trashItem.setTitle(R.string.mnu_comment_delete_permanently); |
| } |
| } |
| |
| return true; |
| } |
| |
| @Override |
| public boolean onActionItemClicked(ActionMode actionMode, MenuItem menuItem) { |
| int numSelected = getSelectedCommentCount(); |
| if (numSelected == 0) |
| return false; |
| |
| int i = menuItem.getItemId(); |
| if (i == R.id.menu_approve) { |
| moderateSelectedComments(CommentStatus.APPROVED); |
| return true; |
| } else if (i == R.id.menu_unapprove) { |
| moderateSelectedComments(CommentStatus.UNAPPROVED); |
| return true; |
| } else if (i == R.id.menu_spam) { |
| moderateSelectedComments(CommentStatus.SPAM); |
| return true; |
| } else if (i == R.id.menu_trash) {// unlike the other status changes, we ask the user to confirm trashing |
| confirmDeleteComments(); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| @Override |
| public void onDestroyActionMode(ActionMode mode) { |
| getAdapter().setEnableSelection(false); |
| mFilteredCommentsView.setSwipeToRefreshEnabled(true); |
| mActionMode = null; |
| } |
| } |
| |
| private CommentAdapter getAdapter() { |
| if (mAdapter == null) { |
| mAdapter = new CommentAdapter(getActivity(), WordPress.getCurrentLocalTableBlogId()); |
| mAdapter.setInitialState(mCommentAdapterState); |
| mAdapter.setOnCommentPressedListener(this); |
| mAdapter.setOnDataLoadedListener(this); |
| mAdapter.setOnLoadMoreListener(this); |
| mAdapter.setOnSelectedItemsChangeListener(this); |
| } |
| |
| return mAdapter; |
| } |
| |
| |
| // adapter calls this when selected comments have changed (CAB) |
| @Override |
| public void onSelectedItemsChanged() { |
| if (mActionMode != null) { |
| if (getSelectedCommentCount() == 0) { |
| mActionMode.finish(); |
| } else { |
| updateActionModeTitle(); |
| // must invalidate to ensure onPrepareActionMode is called |
| mActionMode.invalidate(); |
| } |
| } |
| } |
| |
| @Override |
| public void onCommentPressed(int position, View view) { |
| // if the comment is being moderated ignore the press |
| Comment comment = getAdapter().getItem(position); |
| if (!isCommentSelectable(comment)) { |
| return; |
| } |
| |
| if (mActionMode == null) { |
| mFilteredCommentsView.invalidate(); |
| if (getActivity() instanceof OnCommentSelectedListener) { |
| ((OnCommentSelectedListener) getActivity()).onCommentSelected(comment.commentID); |
| } |
| } else { |
| getAdapter().toggleItemSelected(position, view); |
| } |
| } |
| |
| @Override |
| public void onCommentLongPressed(int position, View view) { |
| // if the comment is being moderated ignore the press |
| Comment comment = getAdapter().getItem(position); |
| if (!isCommentSelectable(comment)) { |
| return; |
| } |
| |
| // enable CAB if it's not already enabled |
| if (mActionMode == null) { |
| if (getActivity() instanceof AppCompatActivity) { |
| ((AppCompatActivity) getActivity()).startSupportActionMode(new ActionModeCallback()); |
| getAdapter().setEnableSelection(true); |
| getAdapter().setItemSelected(position, true, view); |
| } |
| } else { |
| getAdapter().toggleItemSelected(position, view); |
| } |
| } |
| |
| private boolean isCommentSelectable(Comment comment){ |
| return comment != null && !getAdapter().isModeratingCommentId(comment.commentID); |
| } |
| |
| private boolean shouldRestoreCab() { |
| return hasAdapter() && !getAdapter().getSelectedCommentsId().isEmpty() && mActionMode == null; |
| } |
| |
| private void restoreCab() { |
| if (getActivity() instanceof AppCompatActivity) { |
| ((AppCompatActivity) getActivity()).startSupportActionMode(new ActionModeCallback()); |
| updateActionModeTitle(); |
| } |
| } |
| |
| @Override |
| public void onStart() { |
| super.onStart(); |
| EventBus.getDefault().register(this); |
| } |
| |
| @Override |
| public void onStop() { |
| EventBus.getDefault().unregister(this); |
| super.onStop(); |
| } |
| |
| @SuppressWarnings("unused") |
| public void onEventMainThread(CommentEvents.CommentModerationFinishedEvent event) { |
| if (!isAdded()) return; |
| |
| setCommentIsModerating(event.getCommentId(), false); |
| |
| if (!event.isSuccess()) { |
| ToastUtils.showToast(getActivity(), R.string.error_moderate_comment, ToastUtils.Duration.LONG); |
| } |
| |
| if (event.isCommentsRefreshRequired() || event.getNewStatus() != mCommentStatusFilter) { |
| loadComments(); |
| } |
| } |
| |
| @SuppressWarnings("unused") |
| public void onEventMainThread(CommentEvents.CommentsBatchModerationFinishedEvent moderatedComments) { |
| if (!isAdded()) return; |
| |
| if (moderatedComments.getComments().size() > 0) { |
| for (Comment comment : moderatedComments.getComments()) { |
| setCommentIsModerating(comment.commentID, false); |
| } |
| |
| if (moderatedComments.isDeleted()) { |
| getAdapter().deleteComments(moderatedComments.getComments()); |
| } else { |
| getAdapter().replaceComments(moderatedComments.getComments()); |
| } |
| |
| loadComments(); |
| } else { |
| ToastUtils.showToast(getActivity(), R.string.error_moderate_comment); |
| } |
| } |
| |
| |
| // called after comments have been loaded |
| @Override |
| public void onDataLoaded(boolean isEmpty) { |
| if (!isAdded()) return; |
| |
| if (!isEmpty) { |
| // After comments are loaded, we should check if some of them are selected and show CAB if necessary |
| if (shouldRestoreCab()) { |
| restoreCab(); |
| } |
| |
| // Hide the empty view if there are already some displayed comments |
| mFilteredCommentsView.hideEmptyView(); |
| } else if (!mIsUpdatingComments) { |
| // Change LOADING to NO_CONTENT message |
| mFilteredCommentsView.updateEmptyView(EmptyViewMessageType.NO_CONTENT); |
| } |
| } |
| |
| @Override |
| public void onLoadMore() { |
| if (mCanLoadMoreComments && !mIsUpdatingComments) { |
| updateComments(true); |
| } |
| } |
| |
| } |