com.alainesp.fan.sanderson.MainActivity.java Source code

Java tutorial

Introduction

Here is the source code for com.alainesp.fan.sanderson.MainActivity.java

Source

// This file is part of Fan of Sanderson app,
// Copyright (c) 2015-2016 by Alain Espinosa.
// See LICENSE for details.

package com.alainesp.fan.sanderson;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.internal.NavigationMenuItemView;
import android.support.design.internal.NavigationMenuView;
import android.support.design.widget.NavigationView;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v4.widget.TextViewCompat;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;

import java.util.Hashtable;
import java.util.List;

/**
 * The main activity of the application.
 */
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener {
    private boolean isForeground = false;
    /**
     * A static reference to this activity. Used as a context for example.
     */
    public static MainActivity staticRef;
    /**
     * The navigation view of the drawer
     */
    private static NavigationView navigationView = null;

    // In witch state the app is
    public static final String APP_FRAGMENT_INDEX = "app_state";
    private int app_state = APP_STATE_SUMMARY;
    private static final int APP_STATE_ABOUT = -1;
    static final int APP_STATE_SUMMARY = 0;
    static final int APP_STATE_BOOKS = 1;
    static final int APP_STATE_BLOG = 2;
    static final int APP_STATE_EVENTS = 3;
    static final int APP_STATE_TWITTER = 4;
    private static final int APP_STATE_WOK = 5;
    static final int APP_STATE_WOR = 6;
    private static final int APP_STATE_17SHARD = 7;
    private static final int APP_STATE_SETTINGS = 8;

    /**
     * Navigate to a given menu index
     * @param appState The index
     */
    public static void navigateTo(int appState) {
        Menu drawerMenu = navigationView.getMenu();
        MenuItem selectItem;

        //        if(appState >= APP_STATE_WOK && appState <= APP_STATE_WOR)
        //        {
        //            selectItem = drawerMenu.getItem(APP_STATE_WOK).getSubMenu().getItem(appState-APP_STATE_WOK);
        //        }
        //        else
        selectItem = drawerMenu.getItem(appState);

        staticRef.onNavigationItemSelected(selectItem);
    }

    // Handle badge number in the Drawer. This is something of a hack
    private static final int[] badgeNumbers = new int[8];
    /**
     * A hashtable to obtain menu index from the menu text.
     */
    private static final Hashtable<String, Integer> reverseMenuText = new Hashtable<>(32);

    static {
        // Set the badge numbers
        for (int i = 0; i < badgeNumbers.length; i++)
            badgeNumbers[i] = 0;
    }

    /**
     * Set a menu item in the drawer with a badge.
     * @param menuIndex The index of the menu item
     * @param badge The number ot add as a badge
     */
    public static void setBadgeNumber(int menuIndex, int badge) {
        badgeNumbers[menuIndex] = badge;
        setBadgesNumberUI();
    }

    /**
     * Decrement the badge.
     * @param menuIndex The index of the menu item.
     */
    public static void decBadgeNumber(int menuIndex) {
        badgeNumbers[menuIndex]--;
        setBadgesNumberUI();
    }

    /**
     * Set the badge number to all menu items visible
     */
    private static void setBadgesNumberUI() {
        if (navigationView != null) {
            NavigationMenuView v = (NavigationMenuView) navigationView.getChildAt(0);
            Menu drawerMenu = navigationView.getMenu();

            if (v != null)
                // Iterate all children
                for (int childIndex = 0; childIndex < v.getChildCount(); childIndex++) {
                    View v1 = v.getChildAt(childIndex);
                    if (v1 instanceof NavigationMenuItemView) {
                        TextView mTextView = (TextView) ((NavigationMenuItemView) v1).getChildAt(0);
                        if (mTextView != null) {
                            // Get the menu index
                            Integer menuIndex = reverseMenuText.get(mTextView.getText().toString());
                            if (menuIndex != null && menuIndex < badgeNumbers.length) {
                                Drawable numberText = null;
                                if (badgeNumbers[menuIndex] > 0) {
                                    int height = mTextView.getHeight();
                                    numberText = new TextDrawable(badgeNumbers[menuIndex], mTextView.getTextSize(),
                                            mTextView.getCurrentTextColor(), height);
                                    numberText.setBounds(0, 0, height, height);
                                }

                                // Similar to NavigationMenuItemView.setIcon
                                Drawable icon = drawerMenu.getItem(menuIndex).getIcon();
                                Drawable.ConstantState state = icon.getConstantState();
                                icon = DrawableCompat.wrap(state == null ? icon : state.newDrawable()).mutate();
                                int mIconSize = navigationView.getContext().getResources().getDimensionPixelSize(
                                        android.support.design.R.dimen.design_navigation_icon_size);
                                icon.setBounds(0, 0, mIconSize, mIconSize);
                                DrawableCompat.setTintList(icon, navigationView.getItemIconTintList());
                                TextViewCompat.setCompoundDrawablesRelative(mTextView, icon, null, numberText,
                                        null);
                            }
                        }
                    }
                }
        }
    }

    /**
     * Initialize the badge numbers
     */
    private static void loadBadgeNumbers() {
        // BlogPosts
        setBadgeNumber(APP_STATE_BLOG, DB.BlogPost.getStatus().countUnread);
        // Events
        setBadgeNumber(APP_STATE_EVENTS, DB.Event.getStatus().countUnread);
        // Books
        setBadgeNumber(APP_STATE_BOOKS, Catalog.Brandon.getUnpublishedBookCount());
        // Twitter
        setBadgeNumber(APP_STATE_TWITTER, DB.Tweet.getStatus().countUnread);
        // WoR Reread
        setBadgeNumber(APP_STATE_WOR, DB.TorRereadPost.getTotalUnread());
    }

    /**
     * A Drawable to show number as a text
     */
    private static class TextDrawable extends Drawable {
        private final float mTextSize;
        private final int height;
        private final Paint paint;

        public TextDrawable(int level, float aTextSize, int aTextColor, int aHeight) {
            mTextSize = aTextSize * 7 / 10;// NOTE: Try to fix the *7/10 patch
            height = aHeight;
            setLevel(level);

            paint = new Paint();
            paint.setColor(aTextColor);
            paint.setTextSize(aTextSize);
            paint.setTextAlign(Paint.Align.RIGHT);
        }

        @Override
        public int getIntrinsicWidth() {
            return height;
        }

        @Override
        public int getIntrinsicHeight() {
            return height;
        }

        @Override
        public void draw(Canvas canvas) {
            if (getLevel() > 0)
                canvas.drawText("" + getLevel(), height, (height + mTextSize) / 2, paint);
        }

        @Override
        public void setAlpha(int alpha) {
        }

        @Override
        public void setColorFilter(ColorFilter colorFilter) {
        }

        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    }

    /**
     * Is an app that can handle this intent?
     * @param intent The intent to check
     * @return If the intent can be handle
     */
    public static boolean isIntentSafe(Intent intent) {
        // Verify it resolves
        PackageManager packageManager = staticRef.getPackageManager();
        List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
        return activities.size() > 0;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        staticRef = this;

        super.onCreate(savedInstanceState);
        DB.currentContext = this;
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(this, drawer, toolbar,
                R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();

        navigationView = (NavigationView) findViewById(R.id.nav_view);
        Menu drawerMenu = navigationView.getMenu();
        // Create the hashtable
        reverseMenuText.clear();
        for (int i = 0; i < drawerMenu.size(); i++)
            reverseMenuText.put(drawerMenu.getItem(i).getTitle().toString(), i);
        navigationView.setNavigationItemSelectedListener(this);
        // 2 listeners to show the badges
        navigationView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
            @Override
            public void onLayoutChange(View vv, int left, int top, int right, int bottom, int oldLeft, int oldTop,
                    int oldRight, int oldBottom) {
                setBadgesNumberUI();
            }
        });
        ((NavigationMenuView) navigationView.getChildAt(0))
                .addOnScrollListener(new RecyclerView.OnScrollListener() {
                    @Override
                    public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                        super.onScrolled(recyclerView, dx, dy);
                        setBadgesNumberUI();
                    }
                });

        // Select Summary at the beginning
        loadBadgeNumbers();
        // Try to load the state in which the app was
        if (savedInstanceState != null)
            app_state = savedInstanceState.getInt(APP_FRAGMENT_INDEX);
        else {
            Intent intent = getIntent();
            if (intent != null)
                app_state = intent.getIntExtra(APP_FRAGMENT_INDEX, -2);

            if (app_state == -2)
                app_state = APP_STATE_SUMMARY;
        }

        if (app_state == APP_STATE_ABOUT)
            onAboutClick(null);
        else
            navigateTo((app_state));
    }

    @Override
    protected void onResume() {
        super.onResume();
        isForeground = true;
    }

    @Override
    protected void onPause() {
        super.onPause();
        isForeground = false;
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putInt(APP_FRAGMENT_INDEX, app_state);

        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);

        loadBadgeNumbers();

        if (savedInstanceState != null)
            app_state = savedInstanceState.getInt(APP_FRAGMENT_INDEX);

        if (app_state == APP_STATE_ABOUT)
            onAboutClick(null);
        else
            navigateTo(app_state);
    }

    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else// Close app when in Summary, otherwise go to Summary. Consider here other navigation possibilities
        {
            if (app_state == APP_STATE_SUMMARY)
                super.onBackPressed();
            else
                navigateTo(APP_STATE_SUMMARY);
        }
    }

    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        // Handle navigation view item clicks here.
        int id = item.getItemId();

        if (!item.isChecked()) {
            if (id != R.id.nav_about) {
                this.setTitle(item.getTitle());
                item.setChecked(true);
            }

            if (id == R.id.nav_main) {
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new SummaryFragment()).commit();
                app_state = APP_STATE_SUMMARY;
            } else if (id == R.id.nav_blog) {
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new BlogPostsFragment())
                        .commit();
                app_state = APP_STATE_BLOG;
            } else if (id == R.id.nav_events) {
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new EventsFragment()).commit();
                app_state = APP_STATE_EVENTS;
            } else if (id == R.id.nav_books) {
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new BooksFragment()).commit();
                app_state = APP_STATE_BOOKS;
            } else if (id == R.id.nav_twitter) {
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new TwitterFragment()).commit();
                app_state = APP_STATE_TWITTER;
            } else if (id == R.id.nav_tor0) {
                Uri webpage = Uri.parse("http://www.tor.com/features/series/the-way-of-kings-reread-on-torcom/");
                Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
                if (isIntentSafe(webIntent))
                    startActivity(webIntent);

                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new TorWoKRereadFragment())
                        .commit();
                app_state = APP_STATE_WOK;
                this.setTitle("The Way of Kings Reread");
            } else if (id == R.id.nav_tor1) {
                //Uri webpage = Uri.parse("http://www.tor.com/series/words-of-radiance-reread-on-torcom/");
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new TorWoRRereadFragment())
                        .commit();
                app_state = APP_STATE_WOR;
                this.setTitle("Words of Radiance Reread");
            } else if (id == R.id.nav_17shard)// TODO: Handle posts and news in the app
            {
                Uri webpage = Uri.parse("http://www.17thshard.com/forum/");
                Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
                if (isIntentSafe(webIntent))
                    startActivity(webIntent);

                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new Shard17thFragment())
                        .commit();
                app_state = APP_STATE_17SHARD;
            } else if (id == R.id.nav_settings) {
                getFragmentManager().beginTransaction().replace(R.id.main_fragment, new SettingsFragment())
                        .commit();
                app_state = APP_STATE_SETTINGS;
            } else if (id == R.id.nav_about) {
                try {
                    new AlertDialog.Builder(this).setTitle("About")
                            .setMessage(Html.fromHtml("<em>Fan of Sanderson</em> "
                                    + getPackageManager().getPackageInfo(getPackageName(), 0).versionName + " BETA"
                                    + "<br/><br/>Application made by fans to fans.<br/><br/>"
                                    + "Developer: Alain Espinosa &lt;alainesp@gmail.com&gt;"))
                            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    dialog.dismiss();
                                }
                            }).create().show();
                } catch (PackageManager.NameNotFoundException ignored) {
                }
            }
        }

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
        return true;
    }

    /**
     * Handle a click to the header of the drawer.
     * @param view Unused.
     */
    public void onAboutClick(View view) {
        app_state = APP_STATE_ABOUT;

        for (int i = 0; i < navigationView.getMenu().size(); i++)
            navigationView.getMenu().getItem(i).setChecked(false);

        setTitle("About Brandon Sanderson");
        getFragmentManager().beginTransaction().replace(R.id.main_fragment, new AboutBrandonFragment()).commit();
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        drawer.closeDrawer(GravityCompat.START);
    }
}