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.InjectView;
import dagger.ObjectGraph;
import rx.functions.Action1;
import rx.subjects.PublishSubject;
public class BibleViewer extends BaseActivity implements Injector {
@ -33,6 +35,9 @@ public class BibleViewer extends BaseActivity implements Injector {
@Inject
BibleViewerPreferences prefs;
@Inject
PublishSubject<BookScrollEvent> scrollEventPublisher;
@InjectView(R.id.navigation_drawer)
BibleMenu bibleMenu;
@ -101,10 +106,29 @@ public class BibleViewer extends BaseActivity implements Injector {
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);
// 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);
}
public void closeMenu() {
drawerLayout.closeDrawers();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.viewer, menu);

View File

@ -16,6 +16,7 @@ import dagger.Provides;
import de.devland.esperandro.Esperandro;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.subjects.PublishSubject;
/**
* Modules used for the BibleViewer activity
@ -92,4 +93,10 @@ public class BibleViewerModules {
BookManager 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 org.bspeice.minimalbible.activity.setInset
import android.support.annotation.LayoutRes
import org.crosswire.jsword.versification.BibleBook
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
@ -31,7 +33,13 @@ class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, a
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)
}
@ -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,
* 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
val menuMappings = b.getVersification().getBooks().map {
Pair(it, b.getVersification().getLastChapter(it))
}
/**
* The listener that should be registered to receive click events
* 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
}
}
fun getGroupIdForBook(b: BibleBook) = menuMappings.indexOf(
menuMappings.first { it.first == b }
)
var groupHighlighted: Int = 0
var childHighlighted: Int = 0
@ -129,7 +124,9 @@ class BibleAdapter(val b: Book) : BaseExpandableListAdapter() {
chapterStart + 2
val view = ChildItemHolder.init(
getOrInflate(convertView, parent, R.layout.list_bible_menu_child),
chapterStart..chapterEnd
chapterStart..chapterEnd,
menuMappings[group].first,
scrollPublisher
)
return view
@ -170,16 +167,18 @@ class GroupItemHolder(val bindTo: View) {
* 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
*/
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 content2 = bindTo.findViewById(R.id.content2) as TextView
val content3 = bindTo.findViewById(R.id.content3) as TextView
class object {
fun init(v: View, obj: IntRange): View {
fun init(v: View, obj: IntRange, book: BibleBook,
scrollPublisher: PublishSubject<BookScrollEvent>): View {
val holder =
if (v.getTag() != null) v.getTag() as ChildItemHolder
else ChildItemHolder(v)
else ChildItemHolder(v, book, scrollPublisher)
holder.clearViews()
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
// as a result of recycling. There should probably be a different way of doing this,
// 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
*/
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
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)
bibleContent = rootView.findViewById(R.id.bible_content) as RecyclerView
bibleContent setLayoutManager LinearLayoutManager(ctx)
bibleContent setLayoutManager layoutManager
}
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
fun bindScrollHandler(provider: PublishSubject<BookScrollEvent>,
public fun bindScrollHandler(provider: PublishSubject<BookScrollEvent>,
lM: RecyclerView.LayoutManager) {
provider subscribe {
val event = it