[broken] Add initial ExpandableListView navbar

This commit is contained in:
Bradlee Speice 2014-07-22 23:47:16 -04:00
parent a0e9939954
commit 07f6705539
6 changed files with 271 additions and 46 deletions

View File

@ -16,6 +16,7 @@ import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.widget.ExpandableListView;
import android.widget.ListView; import android.widget.ListView;
import com.readystatesoftware.systembartint.SystemBarTintManager; import com.readystatesoftware.systembartint.SystemBarTintManager;
@ -28,6 +29,7 @@ import org.bspeice.minimalbible.R;
* "https://developer.android.com/design/patterns/navigation-drawer.html#Interaction" * "https://developer.android.com/design/patterns/navigation-drawer.html#Interaction"
* > design guidelines</a> for a complete explanation of the behaviors * > design guidelines</a> for a complete explanation of the behaviors
* implemented here. * implemented here.
* TODO: Refactor to allow ExpandableListView
*/ */
public class BaseNavigationDrawerFragment extends Fragment { public class BaseNavigationDrawerFragment extends Fragment {
@ -41,22 +43,18 @@ public class BaseNavigationDrawerFragment extends Fragment {
* user manually expands it. This shared preference tracks this. * user manually expands it. This shared preference tracks this.
*/ */
private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned"; 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). /**
*/ * A pointer to the current callbacks instance (the Activity).
private NavigationDrawerCallbacks mCallbacks; */
private NavigationDrawerCallbacks mCallbacks;
/** /**
* Helper component that ties the action bar to the navigation drawer. * Helper component that ties the action bar to the navigation drawer.
*/ */
private ActionBarDrawerToggle mDrawerToggle; private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout; private DrawerLayout mDrawerLayout;
protected ListView mDrawerListView;
private View mFragmentContainerView; private View mFragmentContainerView;
protected int mCurrentSelectedPosition = 0;
private boolean mFromSavedInstanceState; private boolean mFromSavedInstanceState;
private boolean mUserLearnedDrawer; private boolean mUserLearnedDrawer;
@ -281,8 +279,8 @@ public class BaseNavigationDrawerFragment extends Fragment {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
// This could also be a ScrollView // This could also be a ScrollView
ListView list = (ListView) view.findViewById(R.id.list_nav_drawer); ExpandableListView list = (ExpandableListView) view.findViewById(R.id.list_nav_drawer);
// This could also be set in your layout, allows the list items to // This could also be set in your layout, allows the list items to
// scroll through the bottom padded area (navigation bar) // scroll through the bottom padded area (navigation bar)
list.setClipToPadding(false); list.setClipToPadding(false);
// Sets the padding to the insets (include action bar and navigation bar // Sets the padding to the insets (include action bar and navigation bar

View File

@ -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<Integer, BibleBook> indexableBibleBooks;
Map<BibleBook, Integer> 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<Integer, BibleBook>();
chaptersForBook = new HashMap<BibleBook, Integer>();
final AtomicInteger counter = new AtomicInteger(0);
vUtil.getBooks(book)
.forEach(new Action1<BibleBook>() {
@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<String> 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<String>(convertView);
convertView.setTag(bookHolder);
} else {
bookHolder = (NavItemHolder<String>) 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<Integer> 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<Integer>(convertView);
convertView.setTag(chapterHolder);
} else {
chapterHolder = (NavItemHolder<Integer>) 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<T> {
@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));
}
}
}
}

View File

@ -24,7 +24,8 @@ import rx.functions.Func1;
injects = { injects = {
BibleViewer.class, BibleViewer.class,
BookFragment.class, BookFragment.class,
ViewerNavDrawerFragment.class ViewerNavDrawerFragment.class,
BibleNavAdapter.class
}, },
library = true library = true
) )
@ -35,17 +36,20 @@ public class BibleViewerModules {
this.activity = activity; this.activity = activity;
} }
@Provides @Singleton @Provides
@Singleton
Injector provideInjector() { Injector provideInjector() {
return activity; return activity;
} }
@Provides @Singleton @Provides
@Singleton
BibleViewerPreferences providePrefs() { BibleViewerPreferences providePrefs() {
return Esperandro.getPreferences(BibleViewerPreferences.class, activity); return Esperandro.getPreferences(BibleViewerPreferences.class, activity);
} }
@Provides @Named("MainBook") @Provides
@Named("MainBook")
Book provideMainBook(BookManager bookManager, final BibleViewerPreferences prefs) { Book provideMainBook(BookManager bookManager, final BibleViewerPreferences prefs) {
final AtomicReference<Book> mBook = new AtomicReference<Book>(null); final AtomicReference<Book> mBook = new AtomicReference<Book>(null);
bookManager.getInstalledBooks() bookManager.getInstalledBooks()
@ -60,7 +64,7 @@ public class BibleViewerModules {
public void call(Book book) { public void call(Book book) {
mBook.set(book); mBook.set(book);
} }
},new Action1<Throwable>() { }, new Action1<Throwable>() {
@Override @Override
public void call(Throwable throwable) { public void call(Throwable throwable) {
Log.d("BibleViewerModules", throwable.getLocalizedMessage()); Log.d("BibleViewerModules", throwable.getLocalizedMessage());

View File

@ -4,49 +4,52 @@ import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.AdapterView; import android.widget.ExpandableListView;
import android.widget.ListView;
import org.bspeice.minimalbible.Injector; import org.bspeice.minimalbible.Injector;
import org.bspeice.minimalbible.R; import org.bspeice.minimalbible.R;
import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment;
import org.bspeice.minimalbible.activity.NavDrawerAdapter;
import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil; import org.bspeice.minimalbible.activity.viewer.bookutil.VersificationUtil;
import org.crosswire.jsword.book.Book; import org.crosswire.jsword.book.Book;
import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Named; 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 { public class ViewerNavDrawerFragment extends BaseNavigationDrawerFragment {
@Inject VersificationUtil vUtil; @Inject VersificationUtil vUtil;
@Inject @Named("MainBook") @Inject @Named("MainBook")
Book mainBook; Book mainBook;
ExpandableListView mActualListView;
@Override @Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
((Injector)getActivity()).inject(this); Injector i = (Injector) getActivity();
i.inject(this);
mDrawerListView = (ListView) inflater.inflate( mActualListView = (ExpandableListView) inflater.inflate(
R.layout.fragment_navigation_drawer, container, false); R.layout.fragment_expandable_navigation_drawer, container, false);
mDrawerListView /*
mDrawerListView
.setOnItemClickListener(new AdapterView.OnItemClickListener() { .setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, public void onItemClick(AdapterView<?> parent, View view,
int position, long id) { int position, long id) {
selectItem(position); selectItem(position);
} }
}); });
List<String> bookNames = vUtil.getNiceBookNames(mainBook) */
.toList().toBlocking().first();
mDrawerListView.setAdapter(new NavDrawerAdapter<String>(getActionBar() mActualListView.setAdapter(new BibleNavAdapter(mainBook, i));
.getThemedContext(), bookNames));
mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); mActualListView.setItemChecked(mCurrentSelectedPosition, true);
return mDrawerListView; return mActualListView;
} }
} }

View File

@ -24,13 +24,14 @@ public class VersificationUtil {
add(BibleBook.INTRO_NT); add(BibleBook.INTRO_NT);
}}; }};
// TODO: Cache the versification?
public Versification getVersification(Book b) { public Versification getVersification(Book b) {
return Versifications.instance().getVersification( return Versifications.instance().getVersification(
(String) b.getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION) (String) b.getBookMetaData().getProperty(BookMetaData.KEY_VERSIFICATION)
); );
} }
public Observable<BibleBook> getBookNames(Book b) { public Observable<BibleBook> getBooks(Book b) {
Versification v = getVersification(b); Versification v = getVersification(b);
return Observable.from(IteratorUtil.copyIterator(v.getBookIterator())) return Observable.from(IteratorUtil.copyIterator(v.getBookIterator()))
.filter(new Func1<BibleBook, Boolean>() { .filter(new Func1<BibleBook, Boolean>() {
@ -41,14 +42,21 @@ public class VersificationUtil {
}); });
} }
public Observable<String> getNiceBookNames(final Book b) { public Observable<String> getBookNames(final Book b) {
return getBooks(b)
return getBookNames(b)
.map(new Func1<BibleBook, String>() { .map(new Func1<BibleBook, String>() {
@Override @Override
public String call(BibleBook bibleBook) { 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);
}
} }

View File

@ -0,0 +1,12 @@
<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/list_nav_drawer"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#cccccc"
android:choiceMode="singleChoice"
android:divider="@android:color/transparent"
android:dividerHeight="0dp"
tools:context="org.bspeice.minimalbible.activity.viewer.ViewerNavDrawerFragment">
</ExpandableListView>