Everything now responds to scroll events correctly!

Time for another release shortly, need to add some testing code and likely do some quick refactor work. Pretty happy where everything's at though, honestly.
This commit is contained in:
Bradlee Speice 2014-12-29 01:27:10 -05:00
parent c70c258231
commit 07015fc2ba
4 changed files with 70 additions and 31 deletions

View File

@ -23,6 +23,8 @@ import javax.inject.Named;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.InjectView; import butterknife.InjectView;
import dagger.ObjectGraph; import dagger.ObjectGraph;
import rx.functions.Action1;
import rx.subjects.PublishSubject;
public class BibleViewer extends BaseActivity implements Injector { public class BibleViewer extends BaseActivity implements Injector {
@ -33,6 +35,9 @@ public class BibleViewer extends BaseActivity implements Injector {
@Inject @Inject
BibleViewerPreferences prefs; BibleViewerPreferences prefs;
@Inject
PublishSubject<BookScrollEvent> scrollEventPublisher;
@InjectView(R.id.navigation_drawer) @InjectView(R.id.navigation_drawer)
BibleMenu bibleMenu; BibleMenu bibleMenu;
@ -101,10 +106,29 @@ public class BibleViewer extends BaseActivity implements Injector {
setInsetToolbar(toolbar); setInsetToolbar(toolbar);
// Currently you must set up the menu in exactly this order. Do I need to refactor this?
bibleMenu.setScrollEventPublisher(scrollEventPublisher);
bibleMenu.setBible(mainBook); bibleMenu.setBible(mainBook);
// If a new chapter is selected, make sure we close the drawer
// We can't specify `this` as the subscriber since we can't
// extend Action1
scrollEventPublisher.subscribe(new Action1<BookScrollEvent>() {
@Override
public void call(BookScrollEvent bookScrollEvent) {
closeMenu();
}
});
// Set up the view to respond to scroll events as well. Again, exact order is needed.
bibleContent.setScrollPublisher(scrollEventPublisher);
bibleContent.setBook(mainBook, prefs); bibleContent.setBook(mainBook, prefs);
} }
public void closeMenu() {
drawerLayout.closeDrawers();
}
@Override @Override
public boolean onCreateOptionsMenu(Menu menu) { public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.viewer, menu); getMenuInflater().inflate(R.menu.viewer, menu);

View File

@ -16,6 +16,7 @@ import dagger.Provides;
import de.devland.esperandro.Esperandro; import de.devland.esperandro.Esperandro;
import rx.functions.Action1; import rx.functions.Action1;
import rx.functions.Func1; import rx.functions.Func1;
import rx.subjects.PublishSubject;
/** /**
* Modules used for the BibleViewer activity * Modules used for the BibleViewer activity
@ -92,4 +93,10 @@ public class BibleViewerModules {
BookManager bookManager() { BookManager bookManager() {
return new BookManager(); return new BookManager();
} }
@Provides
@Singleton
PublishSubject<BookScrollEvent> scrollEventPublisher() {
return PublishSubject.create();
}
} }

View File

@ -20,9 +20,11 @@ import android.util.AttributeSet
import kotlin.properties.Delegates import kotlin.properties.Delegates
import org.bspeice.minimalbible.activity.setInset import org.bspeice.minimalbible.activity.setInset
import android.support.annotation.LayoutRes import android.support.annotation.LayoutRes
import org.crosswire.jsword.versification.BibleBook
class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, attrs) { class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, attrs) {
var menuContent: ExpandableListView by Delegates.notNull(); var menuContent: ExpandableListView by Delegates.notNull()
var scrollEventPublisher: PublishSubject<BookScrollEvent> by Delegates.notNull();
{ {
val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
@ -31,7 +33,13 @@ class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, a
menuContent = findViewById(R.id._bible_menu) as ExpandableListView menuContent = findViewById(R.id._bible_menu) as ExpandableListView
} }
fun setBible(b: Book) = menuContent.setAdapter(BibleAdapter(b)) fun setBible(b: Book) {
val adapter = BibleAdapter(b, scrollEventPublisher)
menuContent setAdapter adapter
scrollEventPublisher subscribe {
menuContent.collapseGroup(adapter.getGroupIdForBook(it.b))
}
}
fun placeInset(a: Activity) = setInset(a) fun placeInset(a: Activity) = setInset(a)
} }
@ -48,30 +56,17 @@ class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, a
* TODO: Refactor this so the math parts are separate from the actual override functions, * TODO: Refactor this so the math parts are separate from the actual override functions,
* so it's easier to test. * so it's easier to test.
*/ */
class BibleAdapter(val b: Book) : BaseExpandableListAdapter() { class BibleAdapter(val b: Book, val scrollPublisher: PublishSubject<BookScrollEvent>)
: BaseExpandableListAdapter() {
// Map BibleBooks to the number of chapters they have // Map BibleBooks to the number of chapters they have
val menuMappings = b.getVersification().getBooks().map { val menuMappings = b.getVersification().getBooks().map {
Pair(it, b.getVersification().getLastChapter(it)) Pair(it, b.getVersification().getLastChapter(it))
} }
/** fun getGroupIdForBook(b: BibleBook) = menuMappings.indexOf(
* The listener that should be registered to receive click events menuMappings.first { it.first == b }
* It's created here because we need access to the menuMappings )
*/
fun getMenuClickListener(listener: PublishSubject<BookScrollEvent>) =
object : ExpandableListView.OnChildClickListener {
override fun onChildClick(listView: ExpandableListView?, childView: View?,
groupPosition: Int, childPosition: Int, id: Long): Boolean {
val map = menuMappings[groupPosition]
// childPosition is index-based
// TODO: Figure out why trying chapter 0 triggers a NotImplementedException...
listener onNext BookScrollEvent(map.first, childPosition + 1)
return true; // Event was handled
}
}
var groupHighlighted: Int = 0 var groupHighlighted: Int = 0
var childHighlighted: Int = 0 var childHighlighted: Int = 0
@ -129,7 +124,9 @@ class BibleAdapter(val b: Book) : BaseExpandableListAdapter() {
chapterStart + 2 chapterStart + 2
val view = ChildItemHolder.init( val view = ChildItemHolder.init(
getOrInflate(convertView, parent, R.layout.list_bible_menu_child), getOrInflate(convertView, parent, R.layout.list_bible_menu_child),
chapterStart..chapterEnd chapterStart..chapterEnd,
menuMappings[group].first,
scrollPublisher
) )
return view return view
@ -170,16 +167,18 @@ class GroupItemHolder(val bindTo: View) {
* Bind the child items. There are some funky math things going on since * Bind the child items. There are some funky math things going on since
* we display three chapters per row, check the adapter for more documentation * we display three chapters per row, check the adapter for more documentation
*/ */
class ChildItemHolder(val bindTo: View) { class ChildItemHolder(val bindTo: View, val book: BibleBook,
val scrollPublisher: PublishSubject<BookScrollEvent>) {
val content1 = bindTo.findViewById(R.id.content1) as TextView val content1 = bindTo.findViewById(R.id.content1) as TextView
val content2 = bindTo.findViewById(R.id.content2) as TextView val content2 = bindTo.findViewById(R.id.content2) as TextView
val content3 = bindTo.findViewById(R.id.content3) as TextView val content3 = bindTo.findViewById(R.id.content3) as TextView
class object { class object {
fun init(v: View, obj: IntRange): View { fun init(v: View, obj: IntRange, book: BibleBook,
scrollPublisher: PublishSubject<BookScrollEvent>): View {
val holder = val holder =
if (v.getTag() != null) v.getTag() as ChildItemHolder if (v.getTag() != null) v.getTag() as ChildItemHolder
else ChildItemHolder(v) else ChildItemHolder(v, book, scrollPublisher)
holder.clearViews() holder.clearViews()
holder.bind(obj) holder.bind(obj)
@ -187,6 +186,9 @@ class ChildItemHolder(val bindTo: View) {
} }
} }
fun buildOnClickListener(chapter: Int): View.OnClickListener =
View.OnClickListener { scrollPublisher onNext BookScrollEvent(book, chapter) }
// Clear the views before binding, so that we don't have stale text left // Clear the views before binding, so that we don't have stale text left
// as a result of recycling. There should probably be a different way of doing this, // as a result of recycling. There should probably be a different way of doing this,
// but get something that works first. // but get something that works first.
@ -211,6 +213,8 @@ class ChildItemHolder(val bindTo: View) {
* Set up the view with the data we want to display * Set up the view with the data we want to display
*/ */
fun bind(range: IntRange) = range.forEach { fun bind(range: IntRange) = range.forEach {
getViewForPosition(it) setText it.toString() val view = getViewForPosition(it)
view setText it.toString()
view setOnClickListener buildOnClickListener(it)
} }
} }

View File

@ -22,19 +22,23 @@ import android.support.v7.widget.LinearLayoutManager
import android.widget.LinearLayout import android.widget.LinearLayout
class BibleView(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, attrs) { class BibleView(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, attrs) {
var bibleContent: RecyclerView by Delegates.notNull(); var bibleContent: RecyclerView by Delegates.notNull()
var scrollPublisher: PublishSubject<BookScrollEvent> by Delegates.notNull()
val layoutManager: LinearLayoutManager = LinearLayoutManager(ctx)
val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater;
{ {
val inflater = ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
// Don't attach yet, as we haven't finished setup
val rootView = inflater.inflate(R.layout.view_bible, this, true) val rootView = inflater.inflate(R.layout.view_bible, this, true)
bibleContent = rootView.findViewById(R.id.bible_content) as RecyclerView bibleContent = rootView.findViewById(R.id.bible_content) as RecyclerView
bibleContent setLayoutManager LinearLayoutManager(ctx) bibleContent setLayoutManager layoutManager
} }
fun setBook(b: Book, prefs: BibleViewerPreferences) { fun setBook(b: Book, prefs: BibleViewerPreferences) {
bibleContent setAdapter BookAdapter(b, prefs) val adapter = BookAdapter(b, prefs)
adapter.bindScrollHandler(scrollPublisher, layoutManager)
bibleContent setAdapter adapter
} }
} }
@ -114,7 +118,7 @@ class BookAdapter(val b: Book, val prefs: BibleViewerPreferences)
*/ */
override fun getItemCount(): Int = chapterCount override fun getItemCount(): Int = chapterCount
fun bindScrollHandler(provider: PublishSubject<BookScrollEvent>, public fun bindScrollHandler(provider: PublishSubject<BookScrollEvent>,
lM: RecyclerView.LayoutManager) { lM: RecyclerView.LayoutManager) {
provider subscribe { provider subscribe {
val event = it val event = it