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 b424738..21eeac0 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 @@ -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 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() { + @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); 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 a1154d3..7dd605a 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 @@ -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 scrollEventPublisher() { + return PublishSubject.create(); + } } \ No newline at end of file diff --git a/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleMenu.kt b/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleMenu.kt index 5486a01..ebe0900 100644 --- a/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleMenu.kt +++ b/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleMenu.kt @@ -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 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) +: 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) = - 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) { 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): 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) } } diff --git a/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleView.kt b/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleView.kt index 05b5057..70a41d6 100644 --- a/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleView.kt +++ b/app/src/main/kotlin/org/bspeice/minimalbible/activity/viewer/BibleView.kt @@ -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 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, + public fun bindScrollHandler(provider: PublishSubject, lM: RecyclerView.LayoutManager) { provider subscribe { val event = it