com.btmura.android.reddit.app.CommentListController.java Source code

Java tutorial

Introduction

Here is the source code for com.btmura.android.reddit.app.CommentListController.java

Source

/*
 * Copyright (C) 2013 Brian Muramatsu
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.btmura.android.reddit.app;

import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.content.Loader;
import android.text.TextUtils;
import android.util.SparseBooleanArray;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;

import com.btmura.android.reddit.R;
import com.btmura.android.reddit.accounts.AccountUtils;
import com.btmura.android.reddit.app.CommentLogic.CommentList;
import com.btmura.android.reddit.content.AccountPrefs;
import com.btmura.android.reddit.content.CommentLoader;
import com.btmura.android.reddit.database.Things;
import com.btmura.android.reddit.net.Urls;
import com.btmura.android.reddit.provider.Provider;
import com.btmura.android.reddit.util.Strings;
import com.btmura.android.reddit.widget.CommentAdapter;
import com.btmura.android.reddit.widget.ThingView.OnThingViewClickListener;

/**
 * Controller that handles all the logic required by {@link
 * CommentListFragment}.
 */
class CommentListController implements Controller<CommentAdapter>, Filterable, CommentList {

    static final String EXTRA_ACCOUNT_NAME = "accountName";
    static final String EXTRA_THING_ID = "thingId";
    static final String EXTRA_LINK_ID = "linkId";
    static final String EXTRA_FILTER = "filter";
    static final String EXTRA_CURSOR_EXTRAS = "cursorExtras";

    private final Context context;
    private final String accountName;
    private final String thingId;
    private final String linkId;
    private final CommentAdapter adapter;
    private int filter;
    private Bundle cursorExtras;

    CommentListController(Context context, Bundle args, OnThingViewClickListener listener) {
        this.context = context;
        this.accountName = getAccountNameExtra(args);
        this.thingId = getThingIdExtra(args);
        this.linkId = getLinkIdExtra(args);
        this.adapter = new CommentAdapter(context, accountName, listener);
        restoreInstanceState(args);
    }

    @Override
    public void restoreInstanceState(Bundle savedInstanceState) {
        int defFilter = AccountPrefs.getLastCommentFilter(context, Filter.COMMENTS_BEST);
        this.filter = savedInstanceState.getInt(EXTRA_FILTER, defFilter);
        this.cursorExtras = savedInstanceState.getBundle(EXTRA_CURSOR_EXTRAS);
    }

    @Override
    public void saveInstanceState(Bundle outState) {
        outState.putInt(EXTRA_FILTER, filter);
        outState.putBundle(EXTRA_CURSOR_EXTRAS, cursorExtras);
    }

    @Override
    public Loader<Cursor> createLoader() {
        return new CommentLoader(context, accountName, thingId, linkId, filter, cursorExtras);
    }

    @Override
    public void swapCursor(Cursor cursor) {
        adapter.swapCursor(cursor);
        cursorExtras = cursor != null ? cursor.getExtras() : null;
    }

    @Override
    public CommentAdapter getAdapter() {
        return adapter;
    }

    // Actions to be done on comments.

    public void author(int pos) {
        MenuHelper.startProfileActivity(context, getAuthor(pos));
    }

    public void copyUrl(int pos) {
        MenuHelper.copyUrl(context, getCommentLabel(pos), getCommentUrl(pos));
    }

    private CharSequence getCommentLabel(int pos) {
        String label = pos != 0 ? getBody(pos) : getTitle(0);
        return Strings.ellipsize(label, 50);
    }

    private CharSequence getCommentUrl(int pos) {
        String permaLink = getPermaLink(0);
        String thingId = pos != 0 ? getThingId(pos) : null;
        return Urls.permaLink(permaLink, thingId);
    }

    public void delete(ListView lv) {
        SparseBooleanArray checkedItemPositions = lv.getCheckedItemPositions();
        long[] checkedItemIds = lv.getCheckedItemIds();

        String[] checkedThingIds = new String[checkedItemIds.length];
        boolean[] hasChildren = new boolean[checkedItemIds.length];
        fillCheckedInfo(checkedItemPositions, checkedThingIds, hasChildren);

        Provider.deleteCommentAsync(context, accountName, hasChildren, checkedItemIds, getThingId(0),
                checkedThingIds);
    }

    private void fillCheckedInfo(SparseBooleanArray checkedPositions, String[] checkedThingIds,
            boolean[] hasChildren) {
        int count = adapter.getCount();
        int j = 0;
        for (int i = 0; i < count; i++) {
            if (checkedPositions.get(i)) {
                checkedThingIds[j] = getThingId(i);
                hasChildren[j] = CommentLogic.hasChildren(this, i);
                j++;
            }
        }
    }

    public void edit(int pos) {
        String title = Strings.toString(getCommentLabel(pos));
        String text = getBody(pos);
        String parentThingId = getThingId(0);
        String thingId = getThingId(pos);

        switch (pos) {
        case 0:
            MenuHelper.startEditPostComposer(context, accountName, title, text, parentThingId, thingId);
            break;

        default:
            MenuHelper.startEditCommentComposer(context, accountName, title, text, parentThingId, thingId);
            break;
        }
    }

    public void expandOrCollapse(int pos, long id) {
        if (pos == 0) {
            return; // Don't allow expanding or collapsing on the header comment.
        }

        if (isExpanded(pos)) {
            long[] childIds = CommentLogic.getChildren(this, pos);
            Provider.collapseCommentAsync(context, id, childIds);
        } else {
            long sessionId = getSessionId(pos);
            Provider.expandCommentAsync(context, id, sessionId);
        }
    }

    public void reply(int pos) {
        String messageDestination = getAuthor(pos);
        String title = Strings.toString(getCommentLabel(pos));
        String parentThingId = getThingId(0);
        String thingId = getThingId(pos);
        MenuHelper.startCommentReplyComposer(context, accountName, messageDestination, title, parentThingId,
                thingId);
    }

    public void save(boolean save) {
        ThingBundle thingBundle = save ? getThingBundle(0) : null;
        Provider.saveAsync(context, accountName, thingId, thingBundle, save);
    }

    public void share(int pos) {
        MenuHelper.share(context, getCommentLabel(pos), getCommentUrl(pos));
    }

    public void vote(int action, int pos) {
        // Store additional information when the user votes on the header comment which represents
        // the overall thing so that it appears in the liked and disliked listing when the vote is
        // still pending.
        ThingBundle thingBundle = pos == 0 ? getThingBundle(pos) : null;
        Provider.voteAsync(context, accountName, action, getThingId(pos), thingBundle);
    }

    private ThingBundle getThingBundle(int pos) {
        return ThingBundle.newLinkInstance(getAuthor(pos), getCreatedUtc(pos), getDomain(pos), getDowns(pos),
                getLikes(pos), getKind(pos), getNumComments(pos), isOver18(pos), getPermaLink(pos), getSaved(pos),
                getScore(pos), isSelf(pos), getSubreddit(pos), getThingId(pos), getThumbnailUrl(pos), getTitle(pos),
                getUps(pos), getUrl(pos));
    }

    // Menu preparation methods.

    public void prepareActionMenu(Menu menu, ListView lv, int pos) {
        prepareAuthorActionItem(menu, lv, pos);
        prepareCopyUrlActionItem(menu, lv, pos);
        prepareDeleteActionItem(menu, lv);
        prepareEditActionItem(menu, lv, pos);
        prepareReplyActionItem(menu, lv, pos);
        prepareShareActionItem(menu, lv, pos);
    }

    private void prepareAuthorActionItem(Menu menu, ListView lv, int pos) {
        String author = getAuthor(pos);
        MenuItem item = menu.findItem(R.id.menu_author);
        item.setVisible(MenuHelper.isUserItemVisible(author) && isCheckedCount(lv, 1));
        if (item.isVisible()) {
            item.setTitle(MenuHelper.getUserTitle(context, author));
        }
    }

    private void prepareCopyUrlActionItem(Menu menu, ListView lv, int pos) {
        MenuItem item = menu.findItem(R.id.menu_copy_url);
        item.setVisible(isCheckedCount(lv, 1) && hasThingId(pos));
    }

    private void prepareDeleteActionItem(Menu menu, ListView lv) {
        MenuItem item = menu.findItem(R.id.menu_delete);
        item.setVisible(hasAccount() && isAllDeletable(lv));
    }

    private void prepareEditActionItem(Menu menu, ListView lv, int pos) {
        MenuItem item = menu.findItem(R.id.menu_edit);
        item.setVisible(isCheckedCount(lv, 1) && hasAccount() && hasThingId(pos) && isEditable(pos));
    }

    private void prepareReplyActionItem(Menu menu, ListView lv, int pos) {
        MenuItem item = menu.findItem(R.id.menu_reply);
        item.setVisible(isCheckedCount(lv, 1) && hasAccount() && hasThingId(pos) && isNotDeleted(pos));
    }

    private void prepareShareActionItem(Menu menu, ListView lv, int pos) {
        MenuItem item = menu.findItem(R.id.menu_share_comment);
        item.setVisible(isCheckedCount(lv, 1) && hasThingId(pos));
    }

    // More complicated getters.

    private boolean hasAccount() {
        return AccountUtils.isAccount(accountName);
    }

    private boolean hasThingId(int pos) {
        return !TextUtils.isEmpty(getThingId(pos));
    }

    private boolean isAllDeletable(ListView lv) {
        SparseBooleanArray checked = lv.getCheckedItemPositions();
        int count = adapter.getCount();
        for (int i = 0; i < count; i++) {
            if (checked.get(i) && (!isAuthor(i) || !hasThingId(i))) {
                return false;
            }
        }
        return true;
    }

    private boolean isAuthor(int pos) {
        return accountName.equals(getAuthor(pos));
    }

    private boolean isCheckedCount(ListView lv, int checkedItemCount) {
        return lv.getCheckedItemCount() == checkedItemCount;
    }

    private boolean isEditable(int pos) {
        return isAuthor(pos) && (pos != 0 || isSelf(0));

    }

    private boolean isNotDeleted(int pos) {
        return !Things.DELETED_AUTHOR.equals(getAuthor(pos));
    }

    // Getters for comment attributes.

    private String getAuthor(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_AUTHOR);
    }

    private String getBody(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_BODY);
    }

    private long getCreatedUtc(int pos) {
        return adapter.getLong(pos, CommentLoader.INDEX_CREATED_UTC);
    }

    private String getDomain(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_DOMAIN);
    }

    private int getDowns(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_DOWNS);
    }

    private int getKind(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_KIND);
    }

    private int getLikes(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_LIKES);
    }

    private long getId(int pos) {
        return adapter.getLong(pos, CommentLoader.INDEX_ID);
    }

    private int getNesting(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_NESTING);
    }

    private int getNumComments(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_NUM_COMMENTS);
    }

    private String getPermaLink(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_PERMA_LINK);
    }

    private boolean getSaved(int pos) {
        return adapter.getBoolean(pos, CommentLoader.INDEX_SAVED);
    }

    private int getScore(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_SCORE);
    }

    private int getSequence(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_SEQUENCE);
    }

    private long getSessionId(int pos) {
        return adapter.getLong(pos, CommentLoader.INDEX_SESSION_ID);
    }

    private String getSubreddit(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_SUBREDDIT);
    }

    private String getThingId(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_THING_ID);
    }

    private String getThumbnailUrl(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_THUMBNAIL_URL);
    }

    private String getTitle(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_TITLE);
    }

    private int getUps(int pos) {
        return adapter.getInt(pos, CommentLoader.INDEX_UPS);
    }

    private String getUrl(int pos) {
        return adapter.getString(pos, CommentLoader.INDEX_URL);
    }

    private boolean isExpanded(int pos) {
        return adapter.getBoolean(pos, CommentLoader.INDEX_EXPANDED);
    }

    private boolean isOver18(int pos) {
        return adapter.getBoolean(pos, CommentLoader.INDEX_OVER_18);
    }

    private boolean isSelf(int pos) {
        return adapter.getBoolean(pos, CommentLoader.INDEX_SELF);
    }

    // Filterable implementation

    @Override
    public int getFilter() {
        return filter;
    }

    @Override
    public void setFilter(int filter) {
        this.filter = filter;
        AccountPrefs.setLastCommentFilter(context, filter);
    }

    // CommentList implementation

    @Override
    public int getCommentCount() {
        return adapter.getCount();
    }

    @Override
    public long getCommentId(int pos) {
        return getId(pos);
    }

    @Override
    public int getCommentNesting(int pos) {
        return getNesting(pos);
    }

    @Override
    public int getCommentSequence(int pos) {
        return getSequence(pos);
    }

    // Getters for extras.

    private static String getAccountNameExtra(Bundle extras) {
        return extras.getString(EXTRA_ACCOUNT_NAME);
    }

    private static String getThingIdExtra(Bundle extras) {
        return extras.getString(EXTRA_THING_ID);
    }

    private static String getLinkIdExtra(Bundle extras) {
        return extras.getString(EXTRA_LINK_ID);
    }
}