From 787cc4aa24faca62e168fd4833921e1c8e201d4b Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Wed, 23 Jul 2014 23:02:48 -0400 Subject: [PATCH] [broken] Significant refactoring work Last step is getting the downloader back up to speed. --- .../BaseNavigationDrawerFragment.java | 301 ------------------ .../activity/downloader/DownloadActivity.java | 135 ++++---- .../downloader/DownloadNavDrawerFragment.java | 47 ++- .../ExpListNavAdapter.java} | 83 ++--- .../ListNavAdapter.java} | 14 +- .../navigation/NavDrawerFragment.java | 299 +++++++++++++++++ .../activity/viewer/BibleViewer.java | 20 +- .../activity/viewer/BibleViewerModules.java | 5 +- .../viewer/ExpListNavDrawerFragment.java | 110 +++++++ .../viewer/ViewerNavDrawerFragment.java | 56 ---- .../main/res/layout/activity_bible_viewer.xml | 14 +- .../fragment_expandable_navigation_drawer.xml | 2 +- 12 files changed, 557 insertions(+), 529 deletions(-) delete mode 100644 app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java rename app/src/main/java/org/bspeice/minimalbible/activity/{viewer/BibleNavAdapter.java => navigation/ExpListNavAdapter.java} (63%) rename app/src/main/java/org/bspeice/minimalbible/activity/{NavDrawerAdapter.java => navigation/ListNavAdapter.java} (93%) create mode 100644 app/src/main/java/org/bspeice/minimalbible/activity/navigation/NavDrawerFragment.java create mode 100644 app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java delete mode 100644 app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java deleted file mode 100644 index b0f0e19..0000000 --- a/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java +++ /dev/null @@ -1,301 +0,0 @@ -package org.bspeice.minimalbible.activity; - -import android.app.Activity; -import android.content.SharedPreferences; -import android.content.res.Configuration; -import android.os.Build; -import android.os.Bundle; -import android.preference.PreferenceManager; -import android.support.v4.app.ActionBarDrawerToggle; -import android.support.v4.app.Fragment; -import android.support.v4.view.GravityCompat; -import android.support.v4.widget.DrawerLayout; -import android.support.v7.app.ActionBar; -import android.support.v7.app.ActionBarActivity; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.ExpandableListView; -import android.widget.ListView; - -import com.readystatesoftware.systembartint.SystemBarTintManager; - -import org.bspeice.minimalbible.R; - -/** - * Fragment used for managing interactions for and presentation of a navigation - * drawer. See the design guidelines for a complete explanation of the behaviors - * implemented here. - * TODO: Refactor to allow ExpandableListView - */ -public class BaseNavigationDrawerFragment extends Fragment { - - /** - * Remember the position of the selected item. - */ - private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; - - /** - * Per the design guidelines, you should show the drawer on launch until the - * user manually expands it. This shared preference tracks this. - */ - private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; - protected ListView mDrawerListView; - protected int mCurrentSelectedPosition = 0; - /** - * A pointer to the current callbacks instance (the Activity). - */ - private NavigationDrawerCallbacks mCallbacks; - /** - * Helper component that ties the action bar to the navigation drawer. - */ - private ActionBarDrawerToggle mDrawerToggle; - private DrawerLayout mDrawerLayout; - private View mFragmentContainerView; - private boolean mFromSavedInstanceState; - private boolean mUserLearnedDrawer; - - public BaseNavigationDrawerFragment() { - } - - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - // Read in the flag indicating whether or not the user has demonstrated - // awareness of the - // drawer. See PREF_USER_LEARNED_DRAWER for details. - SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(getActivity()); - mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); - - if (savedInstanceState != null) { - mCurrentSelectedPosition = savedInstanceState - .getInt(STATE_SELECTED_POSITION); - mFromSavedInstanceState = true; - } - - // Select either the default item (0) or the last selected item. - selectItem(mCurrentSelectedPosition); - } - - @Override - public void onActivityCreated(Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - // Indicate that this fragment would like to influence the set of - // actions in the action bar. - setHasOptionsMenu(true); - } - - public boolean isDrawerOpen() { - return mDrawerLayout != null - && mDrawerLayout.isDrawerOpen(mFragmentContainerView); - } - - /** - * Users of this fragment must call this method to set up the navigation - * drawer interactions. - * - * @param fragmentId - * The android:id of this fragment in its activity's layout. - * @param drawerLayout - * The DrawerLayout containing this fragment's UI. - */ - public void setUp(int fragmentId, DrawerLayout drawerLayout) { - mFragmentContainerView = getActivity().findViewById(fragmentId); - mDrawerLayout = drawerLayout; - - // set a custom shadow that overlays the main content when the drawer - // opens - mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, - GravityCompat.START); - // set up the drawer's list view with items and click listener - - ActionBar actionBar = getActionBar(); - actionBar.setDisplayHomeAsUpEnabled(true); - actionBar.setHomeButtonEnabled(true); - - // ActionBarDrawerToggle ties together the the proper interactions - // between the navigation drawer and the action bar app icon. - mDrawerToggle = new ActionBarDrawerToggle(getActivity(), /* host Activity */ - mDrawerLayout, /* DrawerLayout object */ - R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ - R.string.navigation_drawer_open, /* - * "open drawer" description for - * accessibility - */ - R.string.navigation_drawer_close /* - * "close drawer" description for - * accessibility - */ - ) { - @Override - public void onDrawerClosed(View drawerView) { - super.onDrawerClosed(drawerView); - if (!isAdded()) { - return; - } - - getActivity().supportInvalidateOptionsMenu(); // calls - // onPrepareOptionsMenu() - } - - @Override - public void onDrawerOpened(View drawerView) { - super.onDrawerOpened(drawerView); - if (!isAdded()) { - return; - } - - if (!mUserLearnedDrawer) { - // The user manually opened the drawer; store this flag to - // prevent auto-showing - // the navigation drawer automatically in the future. - mUserLearnedDrawer = true; - SharedPreferences sp = PreferenceManager - .getDefaultSharedPreferences(getActivity()); - sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true) - .commit(); - } - - getActivity().supportInvalidateOptionsMenu(); // calls - // onPrepareOptionsMenu() - } - }; - - // If the user hasn't 'learned' about the drawer, open it to introduce - // them to the drawer, - // per the navigation drawer design guidelines. - if (!mUserLearnedDrawer && !mFromSavedInstanceState) { - mDrawerLayout.openDrawer(mFragmentContainerView); - } - - // Defer code dependent on restoration of previous instance state. - mDrawerLayout.post(new Runnable() { - @Override - public void run() { - mDrawerToggle.syncState(); - } - }); - - mDrawerLayout.setDrawerListener(mDrawerToggle); - } - - public void selectItem(int position) { - mCurrentSelectedPosition = position; - if (mDrawerListView != null) { - mDrawerListView.setItemChecked(position, true); - ((NavDrawerAdapter)mDrawerListView.getAdapter()).setCurrentlyHighlighted(position); - } - if (mDrawerLayout != null) { - mDrawerLayout.closeDrawer(mFragmentContainerView); - } - if (mCallbacks != null) { - mCallbacks.onNavigationDrawerItemSelected(position); - } - } - - @Override - public void onAttach(Activity activity) { - super.onAttach(activity); - try { - mCallbacks = (NavigationDrawerCallbacks) activity; - } catch (ClassCastException e) { - throw new ClassCastException( - "Activity must implement NavigationDrawerCallbacks."); - } - } - - @Override - public void onDetach() { - super.onDetach(); - mCallbacks = null; - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - super.onConfigurationChanged(newConfig); - // Forward the new configuration the drawer toggle component. - mDrawerToggle.onConfigurationChanged(newConfig); - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - // If the drawer is open, show the global app actions in the action bar. - // See also - // showGlobalContextActionBar, which controls the top-left area of the - // action bar. - if (mDrawerLayout != null && isDrawerOpen()) { - inflater.inflate(R.menu.global, menu); - showGlobalContextActionBar(); - } - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - if (mDrawerToggle.onOptionsItemSelected(item)) { - return true; - } - return super.onOptionsItemSelected(item); - } - - /** - * Per the navigation drawer design guidelines, updates the action bar to - * show the global app 'context', rather than just what's in the current - * screen. - */ - private void showGlobalContextActionBar() { - ActionBar actionBar = getActionBar(); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - // actionBar.setTitle(R.string.app_name); - } - - protected ActionBar getActionBar() { - return ((ActionBarActivity) getActivity()).getSupportActionBar(); - } - - public void setInsets(View view) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) - return; - SystemBarTintManager tintManager = new SystemBarTintManager(getActivity()); - SystemBarTintManager.SystemBarConfig config = tintManager.getConfig(); - view.setPadding(0, config.getPixelInsetTop(true), - config.getPixelInsetRight(), config.getPixelInsetBottom()); - } - - @Override - public void onViewCreated(View view, Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - - // This could also be a ScrollView - ExpandableListView list = (ExpandableListView) view.findViewById(R.id.list_nav_drawer); - // This could also be set in your layout, allows the list items to - // scroll through the bottom padded area (navigation bar) - list.setClipToPadding(false); - // Sets the padding to the insets (include action bar and navigation bar - // padding for the current device and orientation) - setInsets(list); - } - - /** - * Callbacks interface that all activities using this fragment must - * implement. - */ - public static interface NavigationDrawerCallbacks { - /** - * Called when an item in the navigation drawer is selected. - */ - void onNavigationDrawerItemSelected(int position); - } -} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivity.java b/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivity.java index ad55c73..b3dfa23 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivity.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivity.java @@ -13,7 +13,7 @@ import org.bspeice.minimalbible.MinimalBible; import org.bspeice.minimalbible.OGHolder; import org.bspeice.minimalbible.R; import org.bspeice.minimalbible.activity.BaseActivity; -import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; +import org.bspeice.minimalbible.activity.navigation.NavDrawerFragment; import org.crosswire.jsword.book.BookCategory; import java.util.List; @@ -24,26 +24,23 @@ import javax.inject.Named; import dagger.ObjectGraph; public class DownloadActivity extends BaseActivity implements - BaseNavigationDrawerFragment.NavigationDrawerCallbacks, + NavDrawerFragment.NavigationDrawerCallbacks, Injector { private final String TAG = "DownloadActivity"; - - /** - * Fragment managing the behaviors, interactions and presentation of the - * navigation drawer. - */ - private DownloadNavDrawerFragment mNavigationDrawerFragment; - - /** - * Used to store the last screen title. For use in - * {@link #restoreActionBar()}. - */ - private CharSequence mTitle; - - @Inject @Named("ValidCategories") + @Inject + @Named("ValidCategories") List validCategories; - + /** + * Fragment managing the behaviors, interactions and presentation of the + * navigation drawer. + */ + private DownloadNavDrawerFragment mNavigationDrawerFragment; + /** + * Used to store the last screen title. For use in + * {@link #restoreActionBar()}. + */ + private CharSequence mTitle; private ObjectGraph daObjectGraph; /** @@ -71,68 +68,68 @@ public class DownloadActivity extends BaseActivity implements daObjectGraph.inject(o); } - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); inject(this); - setContentView(R.layout.activity_download); + setContentView(R.layout.activity_download); - mNavigationDrawerFragment = (DownloadNavDrawerFragment) getSupportFragmentManager() - .findFragmentById(R.id.navigation_drawer); - mTitle = getTitle(); + mNavigationDrawerFragment = (DownloadNavDrawerFragment) getSupportFragmentManager() + .findFragmentById(R.id.navigation_drawer); + mTitle = getTitle(); - // Set up the drawer. - mNavigationDrawerFragment.setUp(R.id.navigation_drawer, - (DrawerLayout) findViewById(R.id.drawer_layout)); - } + // Set up the drawer. + mNavigationDrawerFragment.setUp(R.id.navigation_drawer, + (DrawerLayout) findViewById(R.id.drawer_layout)); + } - @Override - public void onNavigationDrawerItemSelected(int position) { - // update the main content by replacing fragments + @Override + public void onNavigationDrawerItemSelected(int position) { + // update the main content by replacing fragments //TODO: Switch to AutoFactory pattern, rather than newInstance() - FragmentManager fragmentManager = getSupportFragmentManager(); - fragmentManager - .beginTransaction() - .replace(R.id.container, - BookListFragment.newInstance(validCategories.get(position))).commit(); - } + FragmentManager fragmentManager = getSupportFragmentManager(); + fragmentManager + .beginTransaction() + .replace(R.id.container, + BookListFragment.newInstance(validCategories.get(position))).commit(); + } - public void onSectionAttached(String category) { - mTitle = category; - } + public void onSectionAttached(String category) { + mTitle = category; + } - public void restoreActionBar() { - ActionBar actionBar = getSupportActionBar(); - actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); - actionBar.setDisplayShowTitleEnabled(true); - actionBar.setTitle(mTitle); - } + public void restoreActionBar() { + ActionBar actionBar = getSupportActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(mTitle); + } - @Override - public boolean onCreateOptionsMenu(Menu menu) { - if (!mNavigationDrawerFragment.isDrawerOpen()) { - // Only show items in the action bar relevant to this screen - // if the drawer is not showing. Otherwise, let the drawer - // decide what to show in the action bar. - getMenuInflater().inflate(R.menu.download, menu); - restoreActionBar(); - return true; - } - return super.onCreateOptionsMenu(menu); - } + @Override + public boolean onCreateOptionsMenu(Menu menu) { + if (!mNavigationDrawerFragment.isDrawerOpen()) { + // Only show items in the action bar relevant to this screen + // if the drawer is not showing. Otherwise, let the drawer + // decide what to show in the action bar. + getMenuInflater().inflate(R.menu.download, menu); + restoreActionBar(); + return true; + } + return super.onCreateOptionsMenu(menu); + } - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - if (id == R.id.action_settings) { - return true; - } - return super.onOptionsItemSelected(item); - } + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + return true; + } + return super.onOptionsItemSelected(item); + } } diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadNavDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadNavDrawerFragment.java index b96a295..e9171f0 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadNavDrawerFragment.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadNavDrawerFragment.java @@ -1,18 +1,16 @@ package org.bspeice.minimalbible.activity.downloader; import android.os.Bundle; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.ListView; import org.bspeice.minimalbible.Injector; import org.bspeice.minimalbible.R; -import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; -import org.bspeice.minimalbible.activity.NavDrawerAdapter; +import org.bspeice.minimalbible.activity.navigation.ListNavAdapter; +import org.bspeice.minimalbible.activity.navigation.NavDrawerFragment; import org.crosswire.jsword.book.BookCategory; import java.util.List; @@ -20,31 +18,32 @@ import java.util.List; import javax.inject.Inject; import javax.inject.Named; -public class DownloadNavDrawerFragment extends BaseNavigationDrawerFragment { +public class DownloadNavDrawerFragment extends NavDrawerFragment { - @Inject @Named("ValidCategories") + @Inject + @Named("ValidCategories") List validCategories; - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - ((Injector)getActivity()).inject(this); + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + ((Injector) getActivity()).inject(this); - mDrawerListView = (ListView) inflater.inflate( - R.layout.fragment_navigation_drawer, container, false); - mDrawerListView - .setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, - int position, long id) { - selectItem(position); - } - }); + mDrawerListView = (ListView) inflater.inflate( + R.layout.fragment_navigation_drawer, container, false); + mDrawerListView + .setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + selectItem(position); + } + }); - mDrawerListView.setAdapter(new NavDrawerAdapter(getActivity(), + mDrawerListView.setAdapter(new ListNavAdapter(getActivity(), validCategories)); - mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); - return mDrawerListView; - } + mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); + return mDrawerListView; + } } diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java b/app/src/main/java/org/bspeice/minimalbible/activity/navigation/ExpListNavAdapter.java similarity index 63% rename from app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java rename to app/src/main/java/org/bspeice/minimalbible/activity/navigation/ExpListNavAdapter.java index 52b571e..c8d400c 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/navigation/ExpListNavAdapter.java @@ -1,4 +1,4 @@ -package org.bspeice.minimalbible.activity.viewer; +package org.bspeice.minimalbible.activity.navigation; import android.content.Context; import android.view.LayoutInflater; @@ -7,61 +7,44 @@ import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; -import org.bspeice.minimalbible.Injector; import org.bspeice.minimalbible.R; -import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; -import org.crosswire.jsword.book.Book; -import org.crosswire.jsword.versification.BibleBook; -import org.crosswire.jsword.versification.Versification; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.inject.Inject; import butterknife.ButterKnife; import butterknife.InjectView; -import rx.functions.Action1; /** * ExpandableListView Navigation Drawer - * TODO: Refactor out to ExpandableNavDrawerAdapter? + * T1 represents Group objects, T2 is child objects + * Not sure if I'll ever actually need to re-use this, but go ahead and make it generic. + * TODO: Document this. */ -public class BibleNavAdapter extends BaseExpandableListAdapter { - - @Inject - VersificationUtil vUtil; - Versification versification; - Book book; +public class ExpListNavAdapter extends BaseExpandableListAdapter { // Now we could technically implement this structure using a LinkedHashMap, but // it's easier both to understand and program if we implement this using two maps. - Map indexableBibleBooks; - Map chaptersForBook; + Map indexableBibleBooks; + Map> chaptersForBook; private int groupHighlighted; private int childHighlighted; - public BibleNavAdapter(final Book b, Injector injector) { - injector.inject(this); - this.book = b; - versification = vUtil.getVersification(book); + public ExpListNavAdapter(List groups, Map> children) { // Let the map know ahead of time how big it will be // int bookCount = versification.getBookCount(); - indexableBibleBooks = new HashMap(); - chaptersForBook = new HashMap(); + indexableBibleBooks = new HashMap(groups.size()); + chaptersForBook = new HashMap>(groups.size()); - final AtomicInteger counter = new AtomicInteger(0); - vUtil.getBooks(book) - .forEach(new Action1() { - @Override - public void call(BibleBook bibleBook) { - indexableBibleBooks.put(counter.getAndIncrement(), bibleBook); - chaptersForBook.put(bibleBook, vUtil.getChapterCount(b, bibleBook)); - } - }); + // Is it terrible that I don't like using an actual for loop? + for (int index = 0; index < groups.size(); index++) { + T1 gItem = groups.get(index); + indexableBibleBooks.put(index, gItem); + chaptersForBook.put(gItem, children.get(gItem)); + } } @Override @@ -71,25 +54,22 @@ public class BibleNavAdapter extends BaseExpandableListAdapter { @Override public int getChildrenCount(int i) { - return chaptersForBook.get(indexableBibleBooks.get(i)); + return chaptersForBook.get(indexableBibleBooks.get(i)).size(); } @Override - public String getGroup(int i) { - return vUtil.getBookName(book, indexableBibleBooks.get(i)); + public T1 getGroup(int i) { + return indexableBibleBooks.get(i); } /** - * Take a shortcut - since the second item is the (indexed) chapter number, - * we just need to add one to remove the off-by-one - * * @param i The group position * @param i2 The child position * @return The child chapter value */ @Override - public Integer getChild(int i, int i2) { - return i2 + 1; + public T2 getChild(int i, int i2) { + return chaptersForBook.get(indexableBibleBooks.get(i)).get(i2); } @Override @@ -104,7 +84,7 @@ public class BibleNavAdapter extends BaseExpandableListAdapter { @Override public boolean hasStableIds() { - return false; + return true; } /** @@ -119,16 +99,16 @@ public class BibleNavAdapter extends BaseExpandableListAdapter { @Override public View getGroupView(int position, boolean expanded, View convertView, ViewGroup parent) { - NavItemHolder bookHolder; + NavItemHolder bookHolder; if (convertView == null || convertView.getTag() == null) { LayoutInflater inflater = (LayoutInflater) parent.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.list_navigation_drawer, parent, false); - bookHolder = new NavItemHolder(convertView); + bookHolder = new NavItemHolder(convertView); convertView.setTag(bookHolder); } else { - bookHolder = (NavItemHolder) convertView.getTag(); + bookHolder = (NavItemHolder) convertView.getTag(); } bookHolder.bind(getGroup(position), position == groupHighlighted); @@ -148,16 +128,16 @@ public class BibleNavAdapter extends BaseExpandableListAdapter { @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { - NavItemHolder chapterHolder; + NavItemHolder chapterHolder; if (convertView == null || convertView.getTag() == null) { LayoutInflater inflater = (LayoutInflater) parent.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflater.inflate(R.layout.list_navigation_drawer, parent, false); - chapterHolder = new NavItemHolder(convertView); + chapterHolder = new NavItemHolder(convertView); convertView.setTag(chapterHolder); } else { - chapterHolder = (NavItemHolder) convertView.getTag(); + chapterHolder = (NavItemHolder) convertView.getTag(); } chapterHolder.bind(getChild(groupPosition, childPosition), @@ -180,8 +160,9 @@ public class BibleNavAdapter extends BaseExpandableListAdapter { /** * Class to hold elements for the navbar - doesn't matter if they're group or child. + * T3 is either T1 or T2, doesn't matter. */ - class NavItemHolder { + class NavItemHolder { @InjectView(R.id.navlist_content) TextView content; @@ -192,7 +173,7 @@ public class BibleNavAdapter extends BaseExpandableListAdapter { ButterKnife.inject(this, v); } - public void bind(T object, boolean highlighted) { + public void bind(T3 object, boolean highlighted) { content.setText(object.toString()); if (highlighted) { content.setTextColor(v.getResources().getColor(R.color.navbar_highlight)); diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/NavDrawerAdapter.java b/app/src/main/java/org/bspeice/minimalbible/activity/navigation/ListNavAdapter.java similarity index 93% rename from app/src/main/java/org/bspeice/minimalbible/activity/NavDrawerAdapter.java rename to app/src/main/java/org/bspeice/minimalbible/activity/navigation/ListNavAdapter.java index 5572fca..2829d1f 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/NavDrawerAdapter.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/navigation/ListNavAdapter.java @@ -1,4 +1,4 @@ -package org.bspeice.minimalbible.activity; +package org.bspeice.minimalbible.activity.navigation; import android.content.Context; import android.view.LayoutInflater; @@ -19,24 +19,24 @@ import butterknife.InjectView; * This class (and its usage) needs some work refactoring, * but the PoC is looking good! */ -public class NavDrawerAdapter extends BaseAdapter { +public class ListNavAdapter extends BaseAdapter { Context context; List objects; int currentlyHighlighted; - public NavDrawerAdapter(Context context, List objects) { + public ListNavAdapter(Context context, List objects) { this.context = context; this.objects = objects; } - public void setCurrentlyHighlighted(int currentlyHighlighted) { - this.currentlyHighlighted = currentlyHighlighted; - } - public int getCurrentlyHighlighted() { return this.currentlyHighlighted; } + public void setCurrentlyHighlighted(int currentlyHighlighted) { + this.currentlyHighlighted = currentlyHighlighted; + } + @Override public int getCount() { return objects.size(); diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/navigation/NavDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/navigation/NavDrawerFragment.java new file mode 100644 index 0000000..fc78aee --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/navigation/NavDrawerFragment.java @@ -0,0 +1,299 @@ +package org.bspeice.minimalbible.activity.navigation; + +import android.app.Activity; +import android.content.SharedPreferences; +import android.content.res.Configuration; +import android.os.Build; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.support.v4.app.ActionBarDrawerToggle; +import android.support.v4.app.Fragment; +import android.support.v4.view.GravityCompat; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.ActionBarActivity; +import android.view.Menu; +import android.view.MenuInflater; +import android.view.MenuItem; +import android.view.View; +import android.widget.ExpandableListView; +import android.widget.ListView; + +import com.readystatesoftware.systembartint.SystemBarTintManager; + +import org.bspeice.minimalbible.R; + +/** + * Fragment used for managing interactions for and presentation of a navigation + * drawer. See the design guidelines for a complete explanation of the behaviors + * implemented here. + * TODO: Refactor to allow ExpandableListView + */ +public class NavDrawerFragment extends Fragment { + + /** + * Remember the position of the selected item. + */ + private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position"; + + /** + * Per the design guidelines, you should show the drawer on launch until the + * user manually expands it. This shared preference tracks this. + */ + private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; + protected ListView mDrawerListView; + protected int mCurrentSelectedPosition = 0; + /** + * A pointer to the current callbacks instance (the Activity). + */ + private NavigationDrawerCallbacks mCallbacks; + /** + * Helper component that ties the action bar to the navigation drawer. + */ + private ActionBarDrawerToggle mDrawerToggle; + private DrawerLayout mDrawerLayout; + private View mFragmentContainerView; + private boolean mFromSavedInstanceState; + private boolean mUserLearnedDrawer; + + public NavDrawerFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + // Read in the flag indicating whether or not the user has demonstrated + // awareness of the + // drawer. See PREF_USER_LEARNED_DRAWER for details. + SharedPreferences sp = PreferenceManager + .getDefaultSharedPreferences(getActivity()); + mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false); + + if (savedInstanceState != null) { + mCurrentSelectedPosition = savedInstanceState + .getInt(STATE_SELECTED_POSITION); + mFromSavedInstanceState = true; + } + + // Select either the default item (0) or the last selected item. + selectItem(mCurrentSelectedPosition); + } + + @Override + public void onActivityCreated(Bundle savedInstanceState) { + super.onActivityCreated(savedInstanceState); + // Indicate that this fragment would like to influence the set of + // actions in the action bar. + setHasOptionsMenu(true); + } + + public boolean isDrawerOpen() { + return mDrawerLayout != null + && mDrawerLayout.isDrawerOpen(mFragmentContainerView); + } + + /** + * Users of this fragment must call this method to set up the navigation + * drawer interactions. + * + * @param fragmentId The android:id of this fragment in its activity's layout. + * @param drawerLayout The DrawerLayout containing this fragment's UI. + */ + public void setUp(int fragmentId, DrawerLayout drawerLayout) { + mFragmentContainerView = getActivity().findViewById(fragmentId); + mDrawerLayout = drawerLayout; + + // set a custom shadow that overlays the main content when the drawer + // opens + mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, + GravityCompat.START); + // set up the drawer's list view with items and click listener + + ActionBar actionBar = getActionBar(); + actionBar.setDisplayHomeAsUpEnabled(true); + actionBar.setHomeButtonEnabled(true); + + // ActionBarDrawerToggle ties together the the proper interactions + // between the navigation drawer and the action bar app icon. + mDrawerToggle = new ActionBarDrawerToggle(getActivity(), /* host Activity */ + mDrawerLayout, /* DrawerLayout object */ + R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */ + R.string.navigation_drawer_open, /* + * "open drawer" description for + * accessibility + */ + R.string.navigation_drawer_close /* + * "close drawer" description for + * accessibility + */ + ) { + @Override + public void onDrawerClosed(View drawerView) { + super.onDrawerClosed(drawerView); + if (!isAdded()) { + return; + } + + getActivity().supportInvalidateOptionsMenu(); // calls + // onPrepareOptionsMenu() + } + + @Override + public void onDrawerOpened(View drawerView) { + super.onDrawerOpened(drawerView); + if (!isAdded()) { + return; + } + + if (!mUserLearnedDrawer) { + // The user manually opened the drawer; store this flag to + // prevent auto-showing + // the navigation drawer automatically in the future. + mUserLearnedDrawer = true; + SharedPreferences sp = PreferenceManager + .getDefaultSharedPreferences(getActivity()); + sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true) + .commit(); + } + + getActivity().supportInvalidateOptionsMenu(); // calls + // onPrepareOptionsMenu() + } + }; + + // If the user hasn't 'learned' about the drawer, open it to introduce + // them to the drawer, + // per the navigation drawer design guidelines. + if (!mUserLearnedDrawer && !mFromSavedInstanceState) { + mDrawerLayout.openDrawer(mFragmentContainerView); + } + + // Defer code dependent on restoration of previous instance state. + mDrawerLayout.post(new Runnable() { + @Override + public void run() { + mDrawerToggle.syncState(); + } + }); + + mDrawerLayout.setDrawerListener(mDrawerToggle); + } + + public void selectItem(int position) { + mCurrentSelectedPosition = position; + if (mDrawerListView != null) { + mDrawerListView.setItemChecked(position, true); + ((ListNavAdapter) mDrawerListView.getAdapter()).setCurrentlyHighlighted(position); + } + if (mDrawerLayout != null) { + mDrawerLayout.closeDrawer(mFragmentContainerView); + } + if (mCallbacks != null) { + mCallbacks.onNavigationDrawerItemSelected(position); + } + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mCallbacks = (NavigationDrawerCallbacks) activity; + } catch (ClassCastException e) { + throw new ClassCastException( + "Activity must implement NavigationDrawerCallbacks."); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mCallbacks = null; + } + + @Override + public void onSaveInstanceState(Bundle outState) { + super.onSaveInstanceState(outState); + outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + super.onConfigurationChanged(newConfig); + // Forward the new configuration the drawer toggle component. + mDrawerToggle.onConfigurationChanged(newConfig); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + // If the drawer is open, show the global app actions in the action bar. + // See also + // showGlobalContextActionBar, which controls the top-left area of the + // action bar. + if (mDrawerLayout != null && isDrawerOpen()) { + inflater.inflate(R.menu.global, menu); + showGlobalContextActionBar(); + } + super.onCreateOptionsMenu(menu, inflater); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + if (mDrawerToggle.onOptionsItemSelected(item)) { + return true; + } + return super.onOptionsItemSelected(item); + } + + /** + * Per the navigation drawer design guidelines, updates the action bar to + * show the global app 'context', rather than just what's in the current + * screen. + */ + private void showGlobalContextActionBar() { + ActionBar actionBar = getActionBar(); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + // actionBar.setTitle(R.string.app_name); + } + + protected ActionBar getActionBar() { + return ((ActionBarActivity) getActivity()).getSupportActionBar(); + } + + public void setInsets(View view) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) + return; + SystemBarTintManager tintManager = new SystemBarTintManager(getActivity()); + SystemBarTintManager.SystemBarConfig config = tintManager.getConfig(); + view.setPadding(0, config.getPixelInsetTop(true), + config.getPixelInsetRight(), config.getPixelInsetBottom()); + } + + @Override + public void onViewCreated(View view, Bundle savedInstanceState) { + super.onViewCreated(view, savedInstanceState); + + // This could also be a ScrollView + ExpandableListView list = (ExpandableListView) view.findViewById(R.id.list_nav_drawer); + // This could also be set in your layout, allows the list items to + // scroll through the bottom padded area (navigation bar) + list.setClipToPadding(false); + // Sets the padding to the insets (include action bar and navigation bar + // padding for the current device and orientation) + setInsets(list); + } + + /** + * Callbacks interface that all activities using this fragment must + * implement. + */ + public static interface NavigationDrawerCallbacks { + /** + * Called when an item in the navigation drawer is selected. + */ + void onNavigationDrawerItemSelected(int position); + } +} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java index d213a56..f854b6f 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java @@ -16,8 +16,8 @@ import org.bspeice.minimalbible.MinimalBible; import org.bspeice.minimalbible.OGHolder; import org.bspeice.minimalbible.R; import org.bspeice.minimalbible.activity.BaseActivity; -import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; import org.bspeice.minimalbible.activity.downloader.DownloadActivity; +import org.bspeice.minimalbible.activity.navigation.NavDrawerFragment; import org.crosswire.jsword.book.Book; import javax.inject.Inject; @@ -27,7 +27,7 @@ import rx.android.schedulers.AndroidSchedulers; import rx.functions.Action1; public class BibleViewer extends BaseActivity implements - BaseNavigationDrawerFragment.NavigationDrawerCallbacks, + NavDrawerFragment.NavigationDrawerCallbacks, Injector { @Inject BookManager bookManager; @@ -37,7 +37,7 @@ public class BibleViewer extends BaseActivity implements * Fragment managing the behaviors, interactions and presentation of the * navigation drawer. */ - private ViewerNavDrawerFragment mNavigationDrawerFragment; + private ExpListNavDrawerFragment mNavigationDrawerFragment; /** * Used to store the last screen title. For use in * {@link #restoreActionBar()}. @@ -50,13 +50,11 @@ public class BibleViewer extends BaseActivity implements private void buildObjGraph() { if (bvObjectGraph == null) { OGHolder holder = OGHolder.get(this); - ObjectGraph holderGraph = holder.fetchGraph(); - if (holderGraph == null) { + bvObjectGraph = holder.fetchGraph(); + if (bvObjectGraph == null) { bvObjectGraph = MinimalBible.get(this) .plus(new BibleViewerModules(this)); - holder.persistGraph(holderGraph); - } else { - bvObjectGraph = holderGraph; + holder.persistGraph(bvObjectGraph); } } bvObjectGraph.inject(this); @@ -98,9 +96,9 @@ public class BibleViewer extends BaseActivity implements setContentView(R.layout.activity_bible_viewer); - mNavigationDrawerFragment = (ViewerNavDrawerFragment) getSupportFragmentManager() - .findFragmentById(R.id.navigation_drawer); - mTitle = getTitle(); + mNavigationDrawerFragment = (ExpListNavDrawerFragment) getSupportFragmentManager() + .findFragmentById(R.id.navigation_drawer); + mTitle = getTitle(); // Set up the drawer. mNavigationDrawerFragment.setUp(R.id.navigation_drawer, diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java index 0f60ea3..84b4e58 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java @@ -3,6 +3,7 @@ package org.bspeice.minimalbible.activity.viewer; import android.util.Log; import org.bspeice.minimalbible.Injector; +import org.bspeice.minimalbible.activity.navigation.ExpListNavAdapter; import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; import org.crosswire.jsword.book.Book; @@ -24,8 +25,8 @@ import rx.functions.Func1; injects = { BibleViewer.class, BookFragment.class, - ViewerNavDrawerFragment.class, - BibleNavAdapter.class + ExpListNavDrawerFragment.class, + ExpListNavAdapter.class }, library = true ) diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java new file mode 100644 index 0000000..474eab9 --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ExpListNavDrawerFragment.java @@ -0,0 +1,110 @@ +package org.bspeice.minimalbible.activity.viewer; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ExpandableListView; + +import org.bspeice.minimalbible.Injector; +import org.bspeice.minimalbible.R; +import org.bspeice.minimalbible.activity.navigation.ExpListNavAdapter; +import org.bspeice.minimalbible.activity.navigation.NavDrawerFragment; +import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; +import org.crosswire.jsword.book.Book; +import org.crosswire.jsword.versification.BibleBook; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Named; + +import rx.functions.Func1; +import rx.functions.Func2; + +/** + * ExpandableListView for managing books of the Bible. + * We extend from @link{BaseNavigationDrawerFragment} so we can inherit some of the lifecycle + * pieces, but the actual view inflation is done by us. + * TODO: Extend BaseExpNavigationDrawerFragment? + */ +public class ExpListNavDrawerFragment extends NavDrawerFragment { + + @Inject VersificationUtil vUtil; + @Inject @Named("MainBook") + Book mainBook; + + ExpandableListView mActualListView; + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + Injector i = (Injector) getActivity(); + i.inject(this); + + mActualListView = (ExpandableListView) inflater.inflate( + R.layout.fragment_expandable_navigation_drawer, container, false); + /* + mDrawerListView + .setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + selectItem(position); + } + }); + */ + + List bibleBooks = vUtil.getBookNames(mainBook) + .toList().toBlocking().first(); + + + // I really don't like how we build the chapters, but I'm not adding Guava just for Range. + // RXJava does get ridiculous with the angle brackets, you have me there. But Intellij + // folds nicely. + Map> chapterMap = + vUtil.getBooks(mainBook).map(new Func1>>() { + @Override + public Map> call(BibleBook bibleBook) { + // These lines are important + int bookCount = vUtil.getChapterCount(mainBook, bibleBook); + List chapterList = new ArrayList(bookCount); + for (int i = 0; i < bookCount; i++) { + chapterList.add(i + 1); // Index to chapter number + } + // + Map> bookListMap = + new HashMap>(1); + bookListMap.put(vUtil.getBookName(mainBook, bibleBook), chapterList); + return bookListMap; + } + }) + .reduce(new Func2>, + Map>, + Map>>() { + @Override + public Map> + call(Map> acc, + Map> value) { + // These lines are important + acc.putAll(value); + return acc; + // + } + }) + .toBlocking() + .first(); + + + ExpListNavAdapter adapter = + new ExpListNavAdapter(bibleBooks, chapterMap); + + mActualListView.setAdapter(adapter); + + mActualListView.setItemChecked(mCurrentSelectedPosition, true); + return mActualListView; + } +} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java deleted file mode 100644 index c4fff3b..0000000 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java +++ /dev/null @@ -1,56 +0,0 @@ -package org.bspeice.minimalbible.activity.viewer; - -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ExpandableListView; - -import org.bspeice.minimalbible.Injector; -import org.bspeice.minimalbible.R; -import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; -import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; -import org.crosswire.jsword.book.Book; - -import javax.inject.Inject; -import javax.inject.Named; - -/** - * ExpandableListView for managing books of the Bible. - * We extend from @link{BaseNavigationDrawerFragment} so we can inherit some of the lifecycle - * pieces, but the actual view inflation is done by us. - * TODO: Extend BaseExpNavigationDrawerFragment? - */ -public class ViewerNavDrawerFragment extends BaseNavigationDrawerFragment { - - @Inject VersificationUtil vUtil; - @Inject @Named("MainBook") - Book mainBook; - - ExpandableListView mActualListView; - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - Injector i = (Injector) getActivity(); - i.inject(this); - - mActualListView = (ExpandableListView) inflater.inflate( - R.layout.fragment_expandable_navigation_drawer, container, false); - /* - mDrawerListView - .setOnItemClickListener(new AdapterView.OnItemClickListener() { - @Override - public void onItemClick(AdapterView parent, View view, - int position, long id) { - selectItem(position); - } - }); - */ - - mActualListView.setAdapter(new BibleNavAdapter(mainBook, i)); - - mActualListView.setItemChecked(mCurrentSelectedPosition, true); - return mActualListView; - } -} diff --git a/app/src/main/res/layout/activity_bible_viewer.xml b/app/src/main/res/layout/activity_bible_viewer.xml index 043d893..052211f 100644 --- a/app/src/main/res/layout/activity_bible_viewer.xml +++ b/app/src/main/res/layout/activity_bible_viewer.xml @@ -4,7 +4,7 @@ android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent" - tools:context="org.bspeice.minimalbible.activities.viewer.BibleViewer" > + tools:context="org.bspeice.minimalbible.activities.viewer.BibleViewer">