org.quantumbadger.redreader.activities.InboxListingActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.quantumbadger.redreader.activities.InboxListingActivity.java

Source

/*******************************************************************************
 * This file is part of RedReader.
 *
 * RedReader is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * RedReader is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with RedReader.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/

package org.quantumbadger.redreader.activities;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import org.apache.http.StatusLine;
import org.quantumbadger.redreader.R;
import org.quantumbadger.redreader.account.RedditAccount;
import org.quantumbadger.redreader.account.RedditAccountManager;
import org.quantumbadger.redreader.adapters.InboxListingAdapter;
import org.quantumbadger.redreader.cache.CacheManager;
import org.quantumbadger.redreader.cache.CacheRequest;
import org.quantumbadger.redreader.cache.RequestFailureType;
import org.quantumbadger.redreader.common.*;
import org.quantumbadger.redreader.jsonwrap.JsonBufferedArray;
import org.quantumbadger.redreader.jsonwrap.JsonBufferedObject;
import org.quantumbadger.redreader.jsonwrap.JsonValue;
import org.quantumbadger.redreader.reddit.APIResponseHandler;
import org.quantumbadger.redreader.reddit.RedditAPI;
import org.quantumbadger.redreader.reddit.RedditPreparedInboxItem;
import org.quantumbadger.redreader.reddit.prepared.RedditPreparedComment;
import org.quantumbadger.redreader.reddit.prepared.RedditPreparedMessage;
import org.quantumbadger.redreader.reddit.things.RedditMessage;
import org.quantumbadger.redreader.reddit.things.RedditThing;
import org.quantumbadger.redreader.views.liststatus.ErrorView;
import org.quantumbadger.redreader.views.liststatus.LoadingView;

import java.net.URI;
import java.util.EnumSet;
import java.util.UUID;

public final class InboxListingActivity extends BaseActivity {

    private static final int OPTIONS_MENU_MARK_ALL_AS_READ = 0;

    private InboxListingAdapter adapter;

    private LoadingView loadingView;
    private LinearLayout notifications;

    private CacheRequest request;

    private EnumSet<PrefsUtility.AppearanceCommentHeaderItems> headerItems;

    private boolean isModmail = false;

    private final Handler itemHandler = new Handler(Looper.getMainLooper()) {
        @Override
        public void handleMessage(final Message msg) {
            adapter.addItem((RedditPreparedInboxItem) msg.obj);
        }
    };

    // TODO load more on scroll to bottom?

    @Override
    public void onCreate(Bundle savedInstanceState) {

        PrefsUtility.applyTheme(this);
        super.onCreate(savedInstanceState);

        final SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);

        final boolean solidblack = PrefsUtility.appearance_solidblack(this, sharedPreferences)
                && PrefsUtility.appearance_theme(this, sharedPreferences) == PrefsUtility.AppearanceTheme.NIGHT;

        getActionBar().setHomeButtonEnabled(true);
        getActionBar().setDisplayHomeAsUpEnabled(true);

        final String title;

        isModmail = getIntent() != null && getIntent().getBooleanExtra("modmail", false);

        if (!isModmail) {
            title = getString(R.string.mainmenu_inbox);
        } else {
            title = getString(R.string.mainmenu_modmail);
        }

        OptionsMenuUtility.fixActionBar(this, title);

        headerItems = PrefsUtility.appearance_comment_header_items(this, sharedPreferences);
        headerItems.remove(PrefsUtility.AppearanceCommentHeaderItems.SCORE);

        final LinearLayout outer = new LinearLayout(this);
        outer.setOrientation(android.widget.LinearLayout.VERTICAL);

        if (solidblack) {
            outer.setBackgroundColor(Color.BLACK);
        }

        loadingView = new LoadingView(this, getString(R.string.download_waiting), true, true);

        notifications = new LinearLayout(this);
        notifications.setOrientation(android.widget.LinearLayout.VERTICAL);
        notifications.addView(loadingView);

        final ListView lv = new ListView(this);

        lv.setSmoothScrollbarEnabled(false);
        lv.setVerticalFadingEdgeEnabled(false);

        lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

                final Object item = lv.getAdapter().getItem(position);

                if (item != null && item instanceof RedditPreparedInboxItem) {
                    ((RedditPreparedInboxItem) item).handleInboxClick(InboxListingActivity.this);
                }
            }
        });

        adapter = new InboxListingAdapter(this, this);
        lv.setAdapter(adapter);

        registerForContextMenu(lv);

        outer.addView(notifications);
        outer.addView(lv);

        makeFirstRequest(this);

        setContentView(outer);
    }

    public void cancel() {
        if (request != null)
            request.cancel();
    }

    private void makeFirstRequest(final Context context) {

        final RedditAccount user = RedditAccountManager.getInstance(context).getDefaultAccount();
        final CacheManager cm = CacheManager.getInstance(context);

        final URI url;

        if (!isModmail) {
            url = Constants.Reddit.getUri("/message/inbox.json?mark=true&limit=100");
        } else {
            url = Constants.Reddit.getUri("/message/moderator.json?limit=100");
        }

        // TODO parameterise limit
        request = new CacheRequest(url, user, null, Constants.Priority.API_INBOX_LIST, 0,
                CacheRequest.DownloadType.FORCE, Constants.FileType.INBOX_LIST, true, true, true, context) {

            @Override
            protected void onDownloadNecessary() {
            }

            @Override
            protected void onDownloadStarted() {
            }

            @Override
            protected void onCallbackException(final Throwable t) {
                request = null;
                BugReportActivity.handleGlobalError(context, t);
            }

            @Override
            protected void onFailure(final RequestFailureType type, final Throwable t, final StatusLine status,
                    final String readableMessage) {

                request = null;

                if (loadingView != null)
                    loadingView.setDone(R.string.download_failed);

                final RRError error = General.getGeneralErrorForFailure(context, type, t, status, url.toString());
                AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                    public void run() {
                        notifications.addView(new ErrorView(InboxListingActivity.this, error));
                    }
                });

                if (t != null)
                    t.printStackTrace();
            }

            @Override
            protected void onProgress(final boolean authorizationInProgress, final long bytesRead,
                    final long totalBytes) {
            }

            @Override
            protected void onSuccess(final CacheManager.ReadableCacheFile cacheFile, final long timestamp,
                    final UUID session, final boolean fromCache, final String mimetype) {
                request = null;
            }

            @Override
            public void onJsonParseStarted(final JsonValue value, final long timestamp, final UUID session,
                    final boolean fromCache) {

                if (loadingView != null)
                    loadingView.setIndeterminate(R.string.download_downloading);

                // TODO pref (currently 10 mins)
                // TODO xml
                if (fromCache && RRTime.since(timestamp) > 10 * 60 * 1000) {
                    AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                        public void run() {
                            final TextView cacheNotif = new TextView(context);
                            cacheNotif.setText(context.getString(R.string.listing_cached)
                                    + RRTime.formatDateTime(timestamp, context));
                            final int paddingPx = General.dpToPixels(context, 6);
                            final int sidePaddingPx = General.dpToPixels(context, 10);
                            cacheNotif.setPadding(sidePaddingPx, paddingPx, sidePaddingPx, paddingPx);
                            cacheNotif.setTextSize(13f);
                            notifications.addView(cacheNotif);
                            adapter.notifyDataSetChanged();
                        }
                    });
                }

                // TODO {"error": 403} is received for unauthorized subreddits

                try {

                    final JsonBufferedObject root = value.asObject();
                    final JsonBufferedObject data = root.getObject("data");
                    final JsonBufferedArray children = data.getArray("children");

                    for (JsonValue child : children) {

                        final RedditThing thing = child.asObject(RedditThing.class);

                        switch (thing.getKind()) {
                        case COMMENT:
                            final RedditPreparedComment comment = new RedditPreparedComment(
                                    InboxListingActivity.this, thing.asComment(), timestamp, false, null, user,
                                    headerItems);
                            itemHandler.sendMessage(General.handlerMessage(0, comment));

                            break;

                        case MESSAGE:
                            final RedditPreparedMessage message = new RedditPreparedMessage(
                                    InboxListingActivity.this, thing.asMessage(), timestamp);
                            itemHandler.sendMessage(General.handlerMessage(0, message));

                            if (message.src.replies != null
                                    && message.src.replies.getType() == JsonValue.Type.OBJECT) {

                                final JsonBufferedArray replies = message.src.replies.asObject().getObject("data")
                                        .getArray("children");

                                for (JsonValue childMsgValue : replies) {
                                    final RedditMessage childMsgRaw = childMsgValue.asObject(RedditThing.class)
                                            .asMessage();
                                    final RedditPreparedMessage childMsg = new RedditPreparedMessage(
                                            InboxListingActivity.this, childMsgRaw, timestamp);
                                    itemHandler.sendMessage(General.handlerMessage(0, childMsg));
                                }
                            }

                            break;

                        default:
                            throw new RuntimeException("Unknown item in list.");
                        }
                    }

                } catch (Throwable t) {
                    notifyFailure(RequestFailureType.PARSE, t, null, "Parse failure");
                    return;
                }

                if (loadingView != null)
                    loadingView.setDone(R.string.download_done);
            }
        };

        cm.makeRequest(request);
    }

    @Override
    public void onBackPressed() {
        if (General.onBackPressed())
            super.onBackPressed();
    }

    @Override
    public boolean onCreateOptionsMenu(final Menu menu) {
        menu.add(0, OPTIONS_MENU_MARK_ALL_AS_READ, 0, R.string.mark_all_as_read);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(final MenuItem item) {
        switch (item.getItemId()) {
        case OPTIONS_MENU_MARK_ALL_AS_READ:

            RedditAPI.markAllAsRead(CacheManager.getInstance(this),
                    new APIResponseHandler.ActionResponseHandler(this) {
                        @Override
                        protected void onSuccess() {
                            General.quickToast(context, R.string.mark_all_as_read_success);
                        }

                        @Override
                        protected void onCallbackException(final Throwable t) {
                            BugReportActivity.addGlobalError(
                                    new RRError("Mark all as Read failed", "Callback exception", t));
                        }

                        @Override
                        protected void onFailure(final RequestFailureType type, final Throwable t,
                                final StatusLine status, final String readableMessage) {
                            final RRError error = General.getGeneralErrorForFailure(context, type, t, status,
                                    "Reddit API action: Mark all as Read");
                            AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                public void run() {
                                    General.showResultDialog(InboxListingActivity.this, error);
                                }
                            });
                        }

                        @Override
                        protected void onFailure(final APIFailureType type) {

                            final RRError error = General.getGeneralErrorForFailure(context, type);
                            AndroidApi.UI_THREAD_HANDLER.post(new Runnable() {
                                public void run() {
                                    General.showResultDialog(InboxListingActivity.this, error);
                                }
                            });
                        }
                    }, RedditAccountManager.getInstance(this).getDefaultAccount(), this);

            return true;
        case android.R.id.home:
            finish();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }
}