com.antew.redditinpictures.library.ui.RedditFragmentActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.antew.redditinpictures.library.ui.RedditFragmentActivity.java

Source

/*
 * Copyright (C) 2014 Antew
 *
 * 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.antew.redditinpictures.library.ui;

import android.app.DialogFragment;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.LoaderManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.CursorLoader;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.Loader;
import android.database.Cursor;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.support.v4.content.LocalBroadcastManager;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
import butterknife.InjectView;
import com.antew.redditinpictures.library.Constants;
import com.antew.redditinpictures.library.annotation.ForApplication;
import com.antew.redditinpictures.library.database.RedditContract;
import com.antew.redditinpictures.library.dialog.LoginDialogFragment;
import com.antew.redditinpictures.library.dialog.LogoutDialogFragment;
import com.antew.redditinpictures.library.dialog.SaveImageDialogFragment;
import com.antew.redditinpictures.library.event.DownloadImageCompleteEvent;
import com.antew.redditinpictures.library.event.ForcePostRefreshEvent;
import com.antew.redditinpictures.library.event.LoadSubredditEvent;
import com.antew.redditinpictures.library.event.RequestCompletedEvent;
import com.antew.redditinpictures.library.event.RequestInProgressEvent;
import com.antew.redditinpictures.library.event.SaveImageEvent;
import com.antew.redditinpictures.library.model.Age;
import com.antew.redditinpictures.library.model.Category;
import com.antew.redditinpictures.library.model.reddit.LoginData;
import com.antew.redditinpictures.library.model.reddit.PostData;
import com.antew.redditinpictures.library.model.reddit.RedditLoginInformation;
import com.antew.redditinpictures.library.model.reddit.RedditSort;
import com.antew.redditinpictures.library.preferences.RedditInPicturesPreferences;
import com.antew.redditinpictures.library.preferences.SharedPreferencesHelper;
import com.antew.redditinpictures.library.service.RedditService;
import com.antew.redditinpictures.library.ui.base.BaseFragmentActivityWithMenu;
import com.antew.redditinpictures.library.util.BundleUtil;
import com.antew.redditinpictures.library.util.ImageDownloader;
import com.antew.redditinpictures.library.util.Ln;
import com.antew.redditinpictures.library.util.RedditUtil;
import com.antew.redditinpictures.library.util.StringUtil;
import com.antew.redditinpictures.library.util.Strings;
import com.antew.redditinpictures.library.util.SubredditUtil;
import com.antew.redditinpictures.pro.R;
import com.google.analytics.tracking.android.EasyTracker;
import com.google.analytics.tracking.android.MapBuilder;
import com.squareup.otto.Subscribe;
import fr.castorflex.android.smoothprogressbar.SmoothProgressBar;
import javax.inject.Inject;

public class RedditFragmentActivity extends BaseFragmentActivityWithMenu
        implements LoginDialogFragment.LoginDialogListener, LogoutDialogFragment.LogoutDialogListener,
        LoaderManager.LoaderCallbacks<Cursor>, SaveImageDialogFragment.SaveImageDialogListener {
    public static final int SETTINGS_REQUEST = 20;
    @InjectView(R.id.top_progressbar)
    protected SmoothProgressBar mProgressBar;
    @Inject
    protected ImageDownloader mImageDownloader;
    @Inject
    @ForApplication
    protected ConnectivityManager mConnectivityManager;
    private ViewType mActiveViewType = ViewType.LIST;
    private BroadcastReceiver mLoginComplete = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            handleLoginComplete(intent);
        }
    };
    private PostData mPostData;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setMenuDrawerContentView(R.layout.reddit_fragment_activity);
        restoreInstanceState(savedInstanceState);

        // We only need to create a new fragment if we aren't pulling from the back stack.
        if (savedInstanceState == null) {
            initializeActiveView();
        }

        initializeLoaders();

        if (!isNetworkAvailable()) {
            Toast.makeText(this, "No Network Connection Available, Connect to the Internet and Try Again",
                    Toast.LENGTH_LONG).show();
        }

        new SubredditUtil.SetDefaultSubredditsTask(this).execute();
    }

    private void restoreInstanceState(Bundle savedInstanceState) {
        if (savedInstanceState != null) {
            mActiveViewType = ViewType.valueOf(BundleUtil.getString(savedInstanceState,
                    Constants.Extra.EXTRA_ACTIVE_VIEW, ViewType.LIST.toString()));
            mSelectedSubreddit = BundleUtil.getString(savedInstanceState, Constants.Extra.EXTRA_SUBREDDIT,
                    Constants.Reddit.REDDIT_FRONTPAGE);
            mCategory = Category.fromString(BundleUtil.getString(savedInstanceState, Constants.Extra.EXTRA_CATEGORY,
                    Category.HOT.getName()));
            mAge = Age.fromString(
                    BundleUtil.getString(savedInstanceState, Constants.Extra.EXTRA_AGE, Age.TODAY.getAge()));
        }
    }

    private void initializeActiveView() {
        switch (mActiveViewType) {
        case GRID:
            EasyTracker.getInstance(this)
                    .send(MapBuilder
                            .createEvent(Constants.Analytics.Category.INITIALIZE,
                                    Constants.Analytics.Action.IMAGE_VIEW, Constants.Analytics.Label.GRID, null)
                            .build());
            FragmentTransaction gridTrans = getFragmentManager().beginTransaction();
            gridTrans.replace(R.id.content_fragment, getNewImageGridFragment());
            gridTrans.commit();
            break;
        case LIST:
            EasyTracker.getInstance(this)
                    .send(MapBuilder
                            .createEvent(Constants.Analytics.Category.INITIALIZE,
                                    Constants.Analytics.Action.IMAGE_VIEW, Constants.Analytics.Label.LIST, null)
                            .build());
            FragmentTransaction listTrans = getFragmentManager().beginTransaction();
            listTrans.replace(R.id.content_fragment, getNewImageListFragment());
            listTrans.commit();
            break;
        }
    }

    private void initializeLoaders() {
        getLoaderManager().initLoader(Constants.Loader.LOADER_LOGIN, null, this);
    }

    protected boolean isNetworkAvailable() {
        NetworkInfo networkInfo = mConnectivityManager.getActiveNetworkInfo();
        return networkInfo != null && networkInfo.isConnected();
    }

    public Fragment getNewImageGridFragment() {
        return getNewImageGridFragment(mSelectedSubreddit, mCategory, mAge);
    }

    public Fragment getNewImageListFragment() {
        return getNewImageListFragment(mSelectedSubreddit, mCategory, mAge);
    }

    public Fragment getNewImageGridFragment(String subreddit, Category category, Age age) {
        return RedditImageGridFragment.newInstance(subreddit, category, age);
    }

    public Fragment getNewImageListFragment(String subreddit, Category category, Age age) {
        return RedditImageListFragment.newInstance(subreddit, category, age);
    }

    @Override
    protected void onResume() {
        super.onResume();
        registerReceivers();
    }

    @Override
    protected void onPause() {
        super.onPause();
        unregisterReceivers();
    }

    private void unregisterReceivers() {
        if (mLoginComplete != null) {
            LocalBroadcastManager.getInstance(this).unregisterReceiver(mLoginComplete);
        }
    }

    private void registerReceivers() {
        LocalBroadcastManager.getInstance(this).registerReceiver(mLoginComplete,
                new IntentFilter(Constants.Broadcast.BROADCAST_LOGIN_COMPLETE));
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putString(Constants.Extra.EXTRA_ACTIVE_VIEW, mActiveViewType.toString());
        outState.putString(Constants.Extra.EXTRA_SUBREDDIT, mSelectedSubreddit);
        outState.putString(Constants.Extra.EXTRA_CATEGORY, Strings.toString(mCategory));
        outState.putString(Constants.Extra.EXTRA_AGE, Strings.toString(mAge));
        super.onSaveInstanceState(outState);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);

        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);

        MenuItem item;
        // Put a checkmark by the currently selected Category + Age combination
        switch (mCategory) {
        case CONTROVERSIAL:
            switch (mAge) {
            case ALL_TIME:
                item = menu.findItem(R.id.category_controversial_all_time);
                item.setChecked(true);
                break;
            case THIS_HOUR:
                item = menu.findItem(R.id.category_controversial_hour);
                item.setChecked(true);
                break;
            case THIS_MONTH:
                item = menu.findItem(R.id.category_controversial_month);
                item.setChecked(true);
                break;
            case THIS_WEEK:
                item = menu.findItem(R.id.category_controversial_week);
                item.setChecked(true);
                break;
            case THIS_YEAR:
                item = menu.findItem(R.id.category_controversial_year);
                item.setChecked(true);
                break;
            case TODAY:
                item = menu.findItem(R.id.category_controversial_today);
                item.setChecked(true);
                break;
            }
            break;
        case HOT:
            menu.findItem(R.id.category_hot).setChecked(true);
            break;
        case NEW:
            menu.findItem(R.id.category_new).setChecked(true);
            break;
        case RISING:
            menu.findItem(R.id.category_rising).setChecked(true);
            break;
        case TOP:
            switch (mAge) {
            case ALL_TIME:
                item = menu.findItem(R.id.category_top_all_time);
                item.setChecked(true);
                break;
            case THIS_HOUR:
                item = menu.findItem(R.id.category_top_hour);
                item.setChecked(true);
                break;
            case THIS_MONTH:
                item = menu.findItem(R.id.category_top_month);
                item.setChecked(true);
                break;
            case THIS_WEEK:
                item = menu.findItem(R.id.category_top_week);
                item.setChecked(true);
                break;
            case THIS_YEAR:
                item = menu.findItem(R.id.category_top_year);
                item.setChecked(true);
                break;
            case TODAY:
                item = menu.findItem(R.id.category_top_today);
                item.setChecked(true);
                break;
            }
            break;
        default:
            mCategory = Category.HOT;
            mAge = Age.TODAY;
            menu.findItem(R.id.category_hot).setChecked(true);
            break;
        }

        MenuItem loginMenuItem = menu.findItem(R.id.login);
        // If the user is logged in, update the Logout menu item to "Log out <username>"
        if (RedditLoginInformation.isLoggedIn()) {
            loginMenuItem.setTitle(getString(R.string.log_out_) + RedditLoginInformation.getUsername());
            loginMenuItem.setIcon(R.drawable.ic_action_exit_dark);
        } else {
            loginMenuItem.setTitle(R.string.log_on);
            loginMenuItem.setIcon(R.drawable.ic_action_key_dark);
        }

        MenuItem activeViewMenuItem = menu.findItem(R.id.change_view);
        switch (mActiveViewType) {
        case LIST:
            activeViewMenuItem.setIcon(R.drawable.ic_action_tiles_small_dark);
            activeViewMenuItem.setTitle(R.string.view_as_grid);
            break;
        case GRID:
            activeViewMenuItem.setIcon(R.drawable.ic_action_list_2_dark);
            activeViewMenuItem.setTitle(R.string.view_as_list);
            break;
        default:
            break;
        }

        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        item.setChecked(true);

        switch (item.getItemId()) {
        case R.id.change_view:
            switch (mActiveViewType) {
            case LIST:
                EasyTracker.getInstance(this)
                        .send(MapBuilder.createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                                Constants.Analytics.Action.CHANGE_VIEW, Constants.Analytics.Label.GRID, null)
                                .build());
                break;
            case GRID:
                EasyTracker.getInstance(this)
                        .send(MapBuilder.createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                                Constants.Analytics.Action.CHANGE_VIEW, Constants.Analytics.Label.LIST, null)
                                .build());
                break;
            }
            changeViewType(mActiveViewType == ViewType.LIST ? ViewType.GRID : ViewType.LIST);
            return true;
        case R.id.settings:
            EasyTracker.getInstance(this)
                    .send(MapBuilder.createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                            Constants.Analytics.Action.OPEN_SETTINGS, null, null).build());
            startPreferences();
            return true;
        case R.id.refresh_all:
            EasyTracker.getInstance(this)
                    .send(MapBuilder.createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                            Constants.Analytics.Action.REFRESH_POSTS, null, null).build());
            // Notify our image fragment(s) that they need
            // to remove references to the now stale data
            mBus.post(new ForcePostRefreshEvent());
            produceRequestInProgressEvent();
            forceRefreshCurrentSubreddit();
            return true;
        case R.id.login:
            if (RedditLoginInformation.isLoggedIn()) {
                EasyTracker.getInstance(this)
                        .send(MapBuilder
                                .createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                                        Constants.Analytics.Action.LOGIN, Constants.Analytics.Label.LOGGED_IN, null)
                                .build());
            } else {
                EasyTracker.getInstance(this)
                        .send(MapBuilder.createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                                Constants.Analytics.Action.LOGIN, Constants.Analytics.Label.NOT_LOGGED_IN, null)
                                .build());
            }
            handleLoginAndLogout();
            return true;
        // fall through
        case R.id.category_hot:
        case R.id.category_new:
        case R.id.category_rising:
        case R.id.category_top_hour:
        case R.id.category_top_today:
        case R.id.category_top_week:
        case R.id.category_top_month:
        case R.id.category_top_year:
        case R.id.category_top_all_time:
        case R.id.category_controversial_hour:
        case R.id.category_controversial_today:
        case R.id.category_controversial_week:
        case R.id.category_controversial_month:
        case R.id.category_controversial_year:
        case R.id.category_controversial_all_time:
            if (RedditSort.contains(item.getItemId())) {
                produceRequestInProgressEvent();
                RedditSort.SortCriteria sortCriteria = RedditSort.get(item.getItemId());
                EasyTracker
                        .getInstance(
                                this)
                        .send(MapBuilder.createEvent(Constants.Analytics.Category.ACTION_BAR_ACTION,
                                Constants.Analytics.Action.OPEN_SUBREDDIT,
                                mSelectedSubreddit + "/" + Strings.toString(sortCriteria.getCategory()) + "/"
                                        + Strings.toString(sortCriteria.getAge()),
                                null).build());
                loadSubreddit(mSelectedSubreddit, sortCriteria.getCategory(), sortCriteria.getAge());
                return true;
            } else {
                Ln.e("Unable to get sorting criteria for menu item id: " + item.getItemId()
                        + ", unable to load subreddit");
                return super.onOptionsItemSelected(item);
            }
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void subscribeToSubreddit(String subredditName) {
        if (!RedditLoginInformation.isLoggedIn()) {
            showLogin();
        } else {
            RedditService.subscribe(this, subredditName);
        }
    }

    @Override
    protected void unsubscribeToSubreddit(String subredditName) {
        if (!RedditLoginInformation.isLoggedIn()) {
            showLogin();
        } else {
            RedditService.unsubscribe(this, subredditName);
        }
    }

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle paramBundle) {
        switch (id) {
        case Constants.Loader.LOADER_LOGIN:
            return new CursorLoader(this, RedditContract.Login.CONTENT_URI, null, null, null,
                    RedditContract.Login.DEFAULT_SORT);
        default:
            return super.onCreateLoader(id, paramBundle);
        }
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
        switch (loader.getId()) {
        case Constants.Loader.LOADER_LOGIN:
            if (cursor != null) {
                if (cursor.moveToFirst()) {
                    String username = cursor.getString(cursor.getColumnIndex(RedditContract.Login.USERNAME));
                    String cookie = cursor.getString(cursor.getColumnIndex(RedditContract.Login.COOKIE));
                    String modhash = cursor.getString(cursor.getColumnIndex(RedditContract.Login.MODHASH));

                    LoginData data = new LoginData(username, modhash, cookie);
                    if (!data.equals(RedditLoginInformation.getLoginData())) {
                        RedditLoginInformation.setLoginData(data);
                    }

                    invalidateOptionsMenu();
                    new SubredditUtil.SetDefaultSubredditsTask(this).execute();
                    forceRefreshCurrentSubreddit();
                }
            }
            break;
        default:
            super.onLoadFinished(loader, cursor);
            break;
        }
    }

    @Override
    protected void loadSubredditFromMenu(String subreddit) {
        loadSubreddit(subreddit, mCategory, mAge);
    }

    private void changeViewType(ViewType viewType) {
        if (viewType != null) {
            mActiveViewType = viewType;
            switch (mActiveViewType) {
            case GRID:
                FragmentTransaction gridTrans = getFragmentManager().beginTransaction();
                gridTrans.replace(R.id.content_fragment, getNewImageGridFragment());
                gridTrans.commit();
                invalidateOptionsMenu();
                break;
            case LIST:
                FragmentTransaction listTrans = getFragmentManager().beginTransaction();
                listTrans.replace(R.id.content_fragment, getNewImageListFragment());
                listTrans.commit();
                invalidateOptionsMenu();
                break;
            }
        }
    }

    public void startPreferences() {
        Intent intent = new Intent(this, getPreferencesClass());
        intent.putExtra(Constants.Extra.EXTRA_SHOW_NSFW_IMAGES, SharedPreferencesHelper.getShowNsfwImages(this));
        startActivityForResult(intent, SETTINGS_REQUEST);
    }

    protected void produceRequestInProgressEvent() {
        mBus.post(new RequestInProgressEvent());
    }

    public void handleLoginAndLogout() {
        if (!RedditLoginInformation.isLoggedIn()) {
            LoginDialogFragment loginFragment = LoginDialogFragment.newInstance();
            loginFragment.show(getFragmentManager(), Constants.Dialog.DIALOG_LOGIN);
        } else {
            DialogFragment logoutFragment = LogoutDialogFragment.newInstance(RedditLoginInformation.getUsername());
            logoutFragment.show(getFragmentManager(), Constants.Dialog.DIALOG_LOGOUT);
        }
    }

    private void loadSubreddit(String subreddit, Category category, Age age) {
        if (subreddit.equals(Constants.Reddit.REDDIT_FRONTPAGE)
                || subreddit.equals(Constants.Reddit.REDDIT_FRONTPAGE_DISPLAY_NAME)) {
            mSelectedSubreddit = Constants.Reddit.REDDIT_FRONTPAGE;
        } else {
            mSelectedSubreddit = subreddit;
        }

        mCategory = category;
        mAge = age;

        switch (mActiveViewType) {
        case GRID:
            FragmentTransaction gridTrans = getFragmentManager().beginTransaction();
            gridTrans.replace(R.id.content_fragment, getNewImageGridFragment(mSelectedSubreddit, mCategory, mAge));
            gridTrans.addToBackStack(null);
            gridTrans.commit();
            break;
        case LIST:
            FragmentTransaction listTrans = getFragmentManager().beginTransaction();
            listTrans.replace(R.id.content_fragment, getNewImageListFragment(mSelectedSubreddit, mCategory, mAge));
            listTrans.addToBackStack(null);
            listTrans.commit();
            break;
        }

        setActionBarTitle(mSelectedSubreddit, RedditUtil.getSortDisplayString(mCategory, mAge));
    }

    public Class<? extends PreferenceActivity> getPreferencesClass() {
        return RedditInPicturesPreferences.class;
    }

    @Subscribe
    public void requestInProgress(RequestInProgressEvent event) {
        mProgressBar.animate().setDuration(500).alpha(100);
    }

    @Subscribe
    public void requestCompleted(RequestCompletedEvent event) {
        mProgressBar.animate().setDuration(500).alpha(0);
    }

    @Override
    public void onFinishLoginDialog(String username, String password) {
        produceRequestInProgressEvent();
        RedditService.login(this, username, password);
        invalidateOptionsMenu();
    }

    @Override
    public void onFinishLogoutDialog() {
        produceRequestInProgressEvent();
        // Clear out the login data, Reddit API doesn't incorporate sessions into how it works so simply clearing out the cached data does the trick.
        RedditLoginInformation.setLoginData(null);

        // This should really be done async, but we store a maximum of one row
        // on the table and it is reasonably fast as is, around 50ms in my tests.
        getContentResolver().delete(RedditContract.Login.CONTENT_URI, null, null);
        new SubredditUtil.SetDefaultSubredditsTask(this, true).execute();
        invalidateOptionsMenu();
        forceRefreshCurrentSubreddit();
    }

    private void handleLoginComplete(Intent intent) {
        boolean successful = intent.getBooleanExtra(Constants.Extra.EXTRA_SUCCESS, false);
        if (!successful) {
            String username = intent.getStringExtra(Constants.Extra.EXTRA_USERNAME);
            if (Strings.notEmpty(username)) {
                LoginDialogFragment loginFragment = LoginDialogFragment.newInstance(username);
                loginFragment.show(getFragmentManager(), Constants.Dialog.DIALOG_LOGIN);
            }

            String errorMessage = intent.getStringExtra(Constants.Extra.EXTRA_ERROR_MESSAGE);
            Toast.makeText(this, getString(R.string.error) + errorMessage, Toast.LENGTH_SHORT).show();
        }
    }

    protected void produceRequestCompletedEvent() {
        mBus.post(new RequestCompletedEvent());
    }

    @Subscribe
    public void onLoadSubredditEvent(LoadSubredditEvent event) {
        if (event != null) {
            mSelectedSubreddit = event.getSubreddit();
            loadSubreddit(event.getSubreddit(), event.getCategory(), event.getAge());
        }
    }

    @Subscribe
    public void onSaveImageEvent(SaveImageEvent event) {
        mPostData = event.getPostData();
        SaveImageDialogFragment saveImageDialog = SaveImageDialogFragment
                .newInstance(StringUtil.sanitizeFileName(mPostData.getTitle()));
        saveImageDialog.show(getFragmentManager(), Constants.Dialog.DIALOG_GET_FILENAME);
    }

    @Subscribe
    public void onDownloadImageComplete(DownloadImageCompleteEvent event) {
        mPostData = null;
        Ln.i("DownloadImageComplete - filename was: " + event.getFilename());
        Toast.makeText(this, "Image saved as " + event.getFilename(), Toast.LENGTH_SHORT).show();
    }

    @Override
    public void onFinishSaveImageDialog(String filename) {
        mImageDownloader.downloadImage(mPostData.getUrl(), filename);
    }

    private enum ViewType {
        LIST, GRID
    }
}