package me.devsaki.hentoid.abstracts;
import android.annotation.SuppressLint;
import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.annotation.LayoutRes;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import me.devsaki.hentoid.HentoidApp;
import me.devsaki.hentoid.R;
import me.devsaki.hentoid.ui.CompoundAdapter;
import me.devsaki.hentoid.ui.DrawerMenuContents;
import me.devsaki.hentoid.util.ConstsPrefs;
import me.devsaki.hentoid.util.Helper;
import me.devsaki.hentoid.util.LogHelper;
/**
* Created by avluis on 4/11/2016.
* Abstract activity with toolbar and navigation drawer.
* Needs to be extended by any activity that wants to be shown as a top level activity.
* The requirements for a subclass are:
* calling {@link #initializeToolbar()} on onCreate, after setContentView() is called.
* In addition, subclasses must have these layout elements:
* - {@link android.support.v7.widget.Toolbar} with id 'toolbar'.
* - {@link android.support.v4.widget.DrawerLayout} with id 'drawer_layout'.
* - {@link android.widget.ListView} with id 'drawer_list'.
*/
public abstract class DrawerActivity extends BaseActivity {
private static final String TAG = LogHelper.makeLogTag(DrawerActivity.class);
protected Fragment fragment;
private Context cxt;
private DrawerLayout mDrawerLayout;
private ListView mDrawerList;
private DrawerMenuContents mDrawerMenuContents;
private Toolbar mToolbar;
private ActionBarDrawerToggle mDrawerToggle;
private final FragmentManager.OnBackStackChangedListener onBackStackChangedListener =
this::updateDrawerToggle;
private boolean isToolbarInitialized;
private int itemToOpen = -1;
private int currentPos = -1;
private boolean itemTapped;
private DrawerLayout.DrawerListener mDrawerListener;
/**
* Return true if the first-app-run-activities have already been executed.
*
* @param context Context to be used to lookup the {@link SharedPreferences}.
*/
private static boolean isFirstRunProcessComplete(final Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getBoolean(
ConstsPrefs.PREF_WELCOME_DONE, false);
}
/**
* Mark whether this is the first time the first-app-run-processes have run.
*
* @param context Context to be used to edit the {@link SharedPreferences}.
*/
private static void markFirstRunProcessComplete(final Context context) {
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putBoolean(ConstsPrefs.PREF_WELCOME_DONE, true).apply();
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResId());
cxt = HentoidApp.getAppContext();
FragmentManager manager = getSupportFragmentManager();
fragment = manager.findFragmentById(R.id.content_frame);
if (fragment == null) {
fragment = buildFragment();
manager.beginTransaction()
.add(R.id.content_frame, fragment, getFragmentTag())
.commit();
}
}
protected abstract Fragment buildFragment();
protected String getToolbarTitle() {
return Helper.getActivityName(cxt, R.string.app_name);
}
private String getFragmentTag() {
if (fragment != null) {
return fragment.getClass().getSimpleName();
}
return null;
}
@Override
protected void onStart() {
super.onStart();
if (!isToolbarInitialized) {
throw new IllegalStateException(
"You must run super.initializeToolbar at " +
"the end of your onCreate method");
}
}
@SuppressWarnings("SameReturnValue")
@LayoutRes
protected int getLayoutResId() {
return R.layout.activity_hentoid;
}
@Override
public void setTitle(CharSequence title) {
super.setTitle(title);
mToolbar.setTitle(title);
}
@Override
public void setTitle(int titleId) {
super.setTitle(titleId);
mToolbar.setTitle(titleId);
}
protected void initializeToolbar() {
mToolbar = (Toolbar) findViewById(R.id.toolbar);
if (mToolbar == null) {
throw new IllegalStateException(
"Layout is required to include a Toolbar with id " +
"'toolbar'");
} else {
setSupportActionBar(mToolbar);
setupActionBarDrawerToggle();
initializeNavigationDrawer();
isToolbarInitialized = true;
}
}
private void initializeNavigationDrawer() {
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
if (mDrawerLayout != null) {
mDrawerList = (ListView) findViewById(R.id.drawer_list);
if (mDrawerList == null) {
throw new IllegalStateException(
"A layout with a drawerLayout is required to " +
"include a ListView with id 'drawer_list'");
}
mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
mToolbar, R.string.drawer_open, R.string.drawer_close);
mDrawerLayout.addDrawerListener(mDrawerListener);
populateDrawerItems();
updateDrawerToggle();
}
// When the user runs the app for the first time, we want to land them with the
// navigation drawer open. But just the first time.
if (!isFirstRunProcessComplete(this)) {
// first run of the app starts with the nav drawer open
mDrawerLayout.openDrawer(GravityCompat.START);
markFirstRunProcessComplete(this);
}
}
private void setupActionBarDrawerToggle() {
mDrawerListener = new DrawerLayout.DrawerListener() {
@Override
public void onDrawerSlide(View drawerView, float slideOffset) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerSlide(drawerView, slideOffset);
}
@Override
public void onDrawerOpened(View drawerView) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerOpened(drawerView);
if (getSupportActionBar() != null) {
getSupportActionBar().setTitle(getToolbarTitle());
}
}
@SuppressLint("NewApi")
@Override
public void onDrawerClosed(View drawerView) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerClosed(drawerView);
int position = itemToOpen;
if (position >= 0 && itemTapped) {
itemTapped = false;
if (Helper.isAtLeastAPI(Build.VERSION_CODES.JELLY_BEAN)) {
Class activityClass = mDrawerMenuContents.getActivity(position);
Intent intent = new Intent(DrawerActivity.this, activityClass);
Bundle bundle = ActivityOptions.makeCustomAnimation(
DrawerActivity.this, R.anim.fade_in, R.anim.fade_out).toBundle();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent, bundle);
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
} else {
Class activityClass = mDrawerMenuContents.getActivity(position);
startActivity(new Intent(DrawerActivity.this, activityClass));
overridePendingTransition(R.anim.fade_in, R.anim.fade_out);
}
}
}
@Override
public void onDrawerStateChanged(int newState) {
if (mDrawerToggle != null) mDrawerToggle.onDrawerStateChanged(newState);
}
};
}
private void populateDrawerItems() {
mDrawerMenuContents = new DrawerMenuContents(this);
updateDrawerPosition();
final int selectedPosition = currentPos;
final int unselectedColor = ContextCompat.getColor(getApplicationContext(),
R.color.drawer_item_unselected_background);
final int selectedColor = ContextCompat.getColor(getApplicationContext(),
R.color.drawer_item_selected_background);
final CompoundAdapter adapter = new CompoundAdapter(this, mDrawerMenuContents.getItems(),
R.layout.drawer_list_item,
new String[]{DrawerMenuContents.FIELD_TITLE}, new int[]{R.id.drawer_item_title}) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
int color = unselectedColor;
if (position == selectedPosition) {
color = selectedColor;
}
view.setBackgroundColor(color);
return view;
}
};
mDrawerList.setOnItemClickListener((parent, view, position, id) -> {
if (position != selectedPosition) {
mDrawerList.setItemChecked(position, true);
itemToOpen = position;
itemTapped = true;
}
mDrawerLayout.closeDrawers();
});
mDrawerList.setAdapter(adapter);
}
protected void updateDrawerPosition() {
final int selectedPosition = mDrawerMenuContents.getPosition(this.getClass());
updateSelected(selectedPosition);
}
private void updateSelected(int position) {
currentPos = position;
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
@Override
protected void onResume() {
super.onResume();
// Whenever the fragment back stack changes, we may need to update the
// action bar toggle: only top level screens show the hamburger-like icon, inner
// screens - either Activities or fragments - show the "Up" icon instead.
getSupportFragmentManager().addOnBackStackChangedListener(onBackStackChangedListener);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
if (mDrawerToggle != null) {
mDrawerToggle.onConfigurationChanged(newConfig);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Pass the event to ActionBarDrawerToggle, if it returns
// true, then it has handled the app icon touch event
if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item)) {
return true;
}
// If not handled by drawerToggle, home needs to be handled by returning to previous
if (item != null && item.getItemId() == android.R.id.home) {
LogHelper.d(TAG, "sent home");
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
// If the drawer is open, back will close it
if (mDrawerLayout != null && mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
mDrawerLayout.closeDrawers();
return;
}
// Otherwise, it may return to the previous fragment stack
FragmentManager fragmentManager = getSupportFragmentManager();
if (fragmentManager.getBackStackEntryCount() > 0) {
fragmentManager.popBackStack();
} else {
// Lastly, it will rely on the system behavior for back
updateDrawerPosition();
super.onBackPressed();
}
}
@Override
public void onPause() {
super.onPause();
getSupportFragmentManager().removeOnBackStackChangedListener(onBackStackChangedListener);
}
private void updateDrawerToggle() {
if (mDrawerToggle == null) {
return;
}
boolean isRoot = getSupportFragmentManager().getBackStackEntryCount() == 0;
mDrawerToggle.setDrawerIndicatorEnabled(isRoot);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayShowHomeEnabled(!isRoot);
getSupportActionBar().setDisplayHomeAsUpEnabled(!isRoot);
getSupportActionBar().setHomeButtonEnabled(!isRoot);
}
if (isRoot) {
mDrawerToggle.syncState();
}
}
}