From 07f6705539716d5c42c17320505778f0f4a19878 Mon Sep 17 00:00:00 2001 From: Bradlee Speice Date: Tue, 22 Jul 2014 23:47:16 -0400 Subject: [PATCH] [broken] Add initial ExpandableListView navbar --- .../BaseNavigationDrawerFragment.java | 26 ++- .../activity/viewer/BibleNavAdapter.java | 200 ++++++++++++++++++ .../activity/viewer/BibleViewerModules.java | 14 +- .../viewer/ViewerNavDrawerFragment.java | 47 ++-- .../viewer/bookutil/VersificationUtil.java | 18 +- .../fragment_expandable_navigation_drawer.xml | 12 ++ 6 files changed, 271 insertions(+), 46 deletions(-) create mode 100644 app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java create mode 100644 app/src/main/res/layout/fragment_expandable_navigation_drawer.xml diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java index d6135ad..b0f0e19 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/BaseNavigationDrawerFragment.java @@ -16,6 +16,7 @@ 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; @@ -28,6 +29,7 @@ import org.bspeice.minimalbible.R; * "https://developer.android.com/design/patterns/navigation-drawer.html#Interaction" * > design guidelines for a complete explanation of the behaviors * implemented here. + * TODO: Refactor to allow ExpandableListView */ public class BaseNavigationDrawerFragment extends Fragment { @@ -41,22 +43,18 @@ public class BaseNavigationDrawerFragment extends Fragment { * user manually expands it. This shared preference tracks this. */ private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; - - /** - * A pointer to the current callbacks instance (the Activity). - */ - private NavigationDrawerCallbacks mCallbacks; - - /** - * Helper component that ties the action bar to the navigation drawer. + 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; - protected ListView mDrawerListView; private View mFragmentContainerView; - - protected int mCurrentSelectedPosition = 0; private boolean mFromSavedInstanceState; private boolean mUserLearnedDrawer; @@ -281,8 +279,8 @@ public class BaseNavigationDrawerFragment extends Fragment { super.onViewCreated(view, savedInstanceState); // This could also be a ScrollView - ListView list = (ListView) view.findViewById(R.id.list_nav_drawer); - // This could also be set in your layout, allows the list items to + 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 diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java new file mode 100644 index 0000000..5ba17cc --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleNavAdapter.java @@ -0,0 +1,200 @@ +package org.bspeice.minimalbible.activity.viewer; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +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.Map; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.inject.Inject; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import rx.functions.Action1; + +public class BibleNavAdapter extends BaseExpandableListAdapter { + + @Inject + VersificationUtil vUtil; + Versification versification; + Book book; + + // 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; + + private int groupHighlighted; + private int childHighlighted; + + public BibleNavAdapter(final Book b, Injector injector) { + injector.inject(this); + this.book = b; + versification = vUtil.getVersification(book); + + // Let the map know ahead of time how big it will be + // int bookCount = versification.getBookCount(); + indexableBibleBooks = new HashMap(); + chaptersForBook = new HashMap(); + + 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)); + } + }); + } + + @Override + public int getGroupCount() { + return indexableBibleBooks.size(); + } + + @Override + public int getChildrenCount(int i) { + return chaptersForBook.get(indexableBibleBooks.get(i)); + } + + @Override + public String getGroup(int i) { + return vUtil.getBookName(book, 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; + } + + @Override + public long getGroupId(int i) { + return i; + } + + @Override + public long getChildId(int i, int i2) { + return i2; + } + + @Override + public boolean hasStableIds() { + return false; + } + + /** + * Get the views for this group + * + * @param position + * @param expanded + * @param convertView + * @param parent + * @return + */ + @Override + public View getGroupView(int position, boolean expanded, + View convertView, ViewGroup parent) { + 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); + convertView.setTag(bookHolder); + } else { + bookHolder = (NavItemHolder) convertView.getTag(); + } + + bookHolder.bind(getGroup(position), position == groupHighlighted); + return convertView; + } + + /** + * Get the view for a child + * + * @param groupPosition + * @param childPosition + * @param isLastChild + * @param convertView + * @param parent + * @return + */ + @Override + public View getChildView(int groupPosition, int childPosition, + boolean isLastChild, View convertView, ViewGroup parent) { + 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); + convertView.setTag(chapterHolder); + } else { + chapterHolder = (NavItemHolder) convertView.getTag(); + } + + chapterHolder.bind(getChild(groupPosition, childPosition), + childPosition == childHighlighted); + return convertView; + } + + @Override + public boolean isChildSelectable(int i, int i2) { + return true; + } + + public void setGroupHighlighted(int groupHighlighted) { + this.groupHighlighted = groupHighlighted; + } + + public void setChildHighlighted(int childHighlighted) { + this.childHighlighted = childHighlighted; + } + + /** + * Class to hold elements for the navbar - doesn't matter if they're group or child. + */ + class NavItemHolder { + @InjectView(R.id.navlist_content) + TextView content; + + View v; + + public NavItemHolder(View v) { + this.v = v; // Needed for resolving colors below + ButterKnife.inject(this, v); + } + + public void bind(T object, boolean highlighted) { + content.setText(object.toString()); + if (highlighted) { + content.setTextColor(v.getResources().getColor(R.color.navbar_highlight)); + } else { + content.setTextColor(v.getResources().getColor(R.color.navbar_unhighlighted)); + } + } + } +} \ No newline at end of file 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 1ecb7fe..0f60ea3 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 @@ -24,7 +24,8 @@ import rx.functions.Func1; injects = { BibleViewer.class, BookFragment.class, - ViewerNavDrawerFragment.class + ViewerNavDrawerFragment.class, + BibleNavAdapter.class }, library = true ) @@ -35,17 +36,20 @@ public class BibleViewerModules { this.activity = activity; } - @Provides @Singleton + @Provides + @Singleton Injector provideInjector() { return activity; } - @Provides @Singleton + @Provides + @Singleton BibleViewerPreferences providePrefs() { return Esperandro.getPreferences(BibleViewerPreferences.class, activity); } - @Provides @Named("MainBook") + @Provides + @Named("MainBook") Book provideMainBook(BookManager bookManager, final BibleViewerPreferences prefs) { final AtomicReference mBook = new AtomicReference(null); bookManager.getInstalledBooks() @@ -60,7 +64,7 @@ public class BibleViewerModules { public void call(Book book) { mBook.set(book); } - },new Action1() { + }, new Action1() { @Override public void call(Throwable throwable) { Log.d("BibleViewerModules", throwable.getLocalizedMessage()); 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 index 671b81b..2853021 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java @@ -4,49 +4,52 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ListView; +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.NavDrawerAdapter; import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; import org.crosswire.jsword.book.Book; -import java.util.List; - 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. + */ 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)getActivity()).inject(this); + Injector i = (Injector) getActivity(); + i.inject(this); - mDrawerListView = (ListView) inflater.inflate( - R.layout.fragment_navigation_drawer, container, false); - mDrawerListView + 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 bookNames = vUtil.getNiceBookNames(mainBook) - .toList().toBlocking().first(); + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + selectItem(position); + } + }); + */ - mDrawerListView.setAdapter(new NavDrawerAdapter(getActionBar() - .getThemedContext(), bookNames)); + mActualListView.setAdapter(new BibleNavAdapter(mainBook, i)); - mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); - return mDrawerListView; - } + mActualListView.setItemChecked(mCurrentSelectedPosition, true); + return mActualListView; + } } diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/bookutil/VersificationUtil.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/bookutil/VersificationUtil.java index 17f346d..ae2787e 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/bookutil/VersificationUtil.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/bookutil/VersificationUtil.java @@ -24,13 +24,14 @@ public class VersificationUtil { add(BibleBook.INTRO_NT); }}; + // TODO: Cache the versification? public Versification getVersification(Book b) { return Versifications.instance().getVersification( (String) b.getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION) ); } - public Observable getBookNames(Book b) { + public Observable getBooks(Book b) { Versification v = getVersification(b); return Observable.from(IteratorUtil.copyIterator(v.getBookIterator())) .filter(new Func1() { @@ -41,14 +42,21 @@ public class VersificationUtil { }); } - public Observable getNiceBookNames(final Book b) { - - return getBookNames(b) + public Observable getBookNames(final Book b) { + return getBooks(b) .map(new Func1() { @Override public String call(BibleBook bibleBook) { - return getVersification(b).getLongName(bibleBook); + return getBookName(b, bibleBook); } }); } + + public Integer getChapterCount(Book b, BibleBook bibleBook) { + return getVersification(b).getLastChapter(bibleBook); + } + + public String getBookName(Book book, BibleBook bibleBook) { + return getVersification(book).getLongName(bibleBook); + } } diff --git a/app/src/main/res/layout/fragment_expandable_navigation_drawer.xml b/app/src/main/res/layout/fragment_expandable_navigation_drawer.xml new file mode 100644 index 0000000..d8c374a --- /dev/null +++ b/app/src/main/res/layout/fragment_expandable_navigation_drawer.xml @@ -0,0 +1,12 @@ + + + \ No newline at end of file