mirror of
				https://github.com/MinimalBible/MinimalBible
				synced 2025-11-03 18:10:27 -05:00 
			
		
		
		
	Some migration refactoring
These classes were getting too big
This commit is contained in:
		@ -2,21 +2,15 @@ package org.bspeice.minimalbible.activity.viewer
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.content.res.Resources
 | 
			
		||||
import android.support.annotation.LayoutRes
 | 
			
		||||
import android.util.AttributeSet
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.BaseExpandableListAdapter
 | 
			
		||||
import android.widget.ExpandableListView
 | 
			
		||||
import android.widget.LinearLayout
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import org.bspeice.minimalbible.R
 | 
			
		||||
import org.crosswire.jsword.book.Book
 | 
			
		||||
import org.crosswire.jsword.book.bookName
 | 
			
		||||
import org.crosswire.jsword.book.getVersification
 | 
			
		||||
import org.crosswire.jsword.versification.BibleBook
 | 
			
		||||
import org.crosswire.jsword.versification.getBooks
 | 
			
		||||
import rx.subjects.PublishSubject
 | 
			
		||||
 | 
			
		||||
class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, attrs) {
 | 
			
		||||
@ -25,7 +19,7 @@ class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, a
 | 
			
		||||
    val menuContent = contentView.findViewById(R.id._bible_menu) as ExpandableListView
 | 
			
		||||
 | 
			
		||||
    fun doInitialize(b: Book, publisher: PublishSubject<BookScrollEvent>) {
 | 
			
		||||
        val adapter = BibleAdapter(b, publisher)
 | 
			
		||||
        val adapter = BibleMenuAdapter(b, publisher)
 | 
			
		||||
        menuContent setAdapter adapter
 | 
			
		||||
        publisher subscribe {
 | 
			
		||||
            menuContent.collapseGroup(adapter.getGroupIdForBook(it.b))
 | 
			
		||||
@ -33,108 +27,15 @@ class BibleMenu(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, a
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The actual adapter for displaying a book's menu navigation system.
 | 
			
		||||
 * There are a couple of notes about this:
 | 
			
		||||
 *  Books are displayed with one row per BibleBook (Genesis, Exodus, etc.) as the group.
 | 
			
		||||
 *  Within each group, there are 3 chapters listed per row (to save space). In order to
 | 
			
		||||
 *  accommodate this, some slightly funky mathematics have to be used, and this is documented.
 | 
			
		||||
 *  Additionally, it doesn't make a whole lot of sense to genericize this using constants
 | 
			
		||||
 *  unless we go to programmatic layouts, since we still need to know the view ID's ahead of time.
 | 
			
		||||
 *
 | 
			
		||||
 * 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, 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))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getGroupIdForBook(b: BibleBook) = menuMappings.indexOf(
 | 
			
		||||
            menuMappings.first { it.first == b }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    var groupHighlighted: Int = 0
 | 
			
		||||
 | 
			
		||||
    override fun getGroupCount(): Int = menuMappings.count()
 | 
			
		||||
 | 
			
		||||
    fun getChaptersForGroup(group: Int) = menuMappings[group].second
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the number of child views for a given book.
 | 
			
		||||
     * What makes this complicated is that we display 3 chapters per row.
 | 
			
		||||
     * To make sure we include everything and account for integer division,
 | 
			
		||||
     * we have to add a row if the chapter count modulo 3 is not even.
 | 
			
		||||
     */
 | 
			
		||||
    override fun getChildrenCount(group: Int): Int {
 | 
			
		||||
        val chapterCount = getChaptersForGroup(group)
 | 
			
		||||
        return when (chapterCount % 3) {
 | 
			
		||||
            0 -> chapterCount / 3
 | 
			
		||||
            else -> (chapterCount / 3) + 1
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getGroup(group: Int): String = b.bookName(menuMappings[group].first)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the starting chapter number for this child view
 | 
			
		||||
     * In order to account for displaying 3 chapters per line,
 | 
			
		||||
     * we need to multiply by three, and then add 1 for the index offset
 | 
			
		||||
     */
 | 
			
		||||
    override fun getChild(group: Int, child: Int): Int = (child * 3) + 1
 | 
			
		||||
 | 
			
		||||
    override fun getGroupId(group: Int): Long = group.toLong()
 | 
			
		||||
 | 
			
		||||
    override fun getChildId(group: Int, child: Int): Long = child.toLong()
 | 
			
		||||
 | 
			
		||||
    override fun hasStableIds(): Boolean = true
 | 
			
		||||
 | 
			
		||||
    override fun isChildSelectable(group: Int, child: Int): Boolean = true
 | 
			
		||||
 | 
			
		||||
    override fun getGroupView(position: Int, expanded: Boolean,
 | 
			
		||||
                              convertView: View?, parent: ViewGroup): View =
 | 
			
		||||
            GroupItemHolder.init(
 | 
			
		||||
                    getOrInflate(convertView, parent, R.layout.list_bible_menu_group),
 | 
			
		||||
                    getGroup(position),
 | 
			
		||||
                    position == groupHighlighted)
 | 
			
		||||
 | 
			
		||||
    override fun getChildView(group: Int, child: Int, isLast: Boolean,
 | 
			
		||||
                              convertView: View?, parent: ViewGroup): View {
 | 
			
		||||
        val chapterStart = getChild(group, child)
 | 
			
		||||
        val chapterCount = getChaptersForGroup(group)
 | 
			
		||||
        val chapterEnd =
 | 
			
		||||
                if (chapterCount < chapterStart + 2)
 | 
			
		||||
                    chapterCount
 | 
			
		||||
                else
 | 
			
		||||
                    chapterStart + 2
 | 
			
		||||
        val view = ChildItemHolder.init(
 | 
			
		||||
                getOrInflate(convertView, parent, R.layout.list_bible_menu_child),
 | 
			
		||||
                chapterStart..chapterEnd,
 | 
			
		||||
                menuMappings[group].first,
 | 
			
		||||
                scrollPublisher
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return view
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getOrInflate(v: View?, p: ViewGroup, LayoutRes layout: Int) =
 | 
			
		||||
            v ?: (p.getContext()
 | 
			
		||||
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
 | 
			
		||||
                    .inflate(layout, p, false)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class GroupItemHolder(val bindTo: View) {
 | 
			
		||||
class BibleMenuGroup(val bindTo: View) {
 | 
			
		||||
    val content = bindTo.findViewById(R.id.content) as TextView
 | 
			
		||||
    val resources = bindTo.getResources(): Resources
 | 
			
		||||
 | 
			
		||||
    companion object {
 | 
			
		||||
        fun init(v: View, obj: Any, highlighted: Boolean): View {
 | 
			
		||||
            val holder =
 | 
			
		||||
                    if (v.getTag() != null) v.getTag() as GroupItemHolder
 | 
			
		||||
                    else GroupItemHolder(v)
 | 
			
		||||
                    if (v.getTag() != null) v.getTag() as BibleMenuGroup
 | 
			
		||||
                    else BibleMenuGroup(v)
 | 
			
		||||
            holder.bind(obj, highlighted)
 | 
			
		||||
 | 
			
		||||
            return v
 | 
			
		||||
@ -155,7 +56,7 @@ 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, val book: BibleBook,
 | 
			
		||||
class BibleMenuChild(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
 | 
			
		||||
@ -165,8 +66,8 @@ class ChildItemHolder(val bindTo: View, val book: BibleBook,
 | 
			
		||||
        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, book, scrollPublisher)
 | 
			
		||||
                    if (v.getTag() != null) v.getTag() as BibleMenuChild
 | 
			
		||||
                    else BibleMenuChild(v, book, scrollPublisher)
 | 
			
		||||
 | 
			
		||||
            holder.clearViews()
 | 
			
		||||
            holder.bind(obj)
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,108 @@
 | 
			
		||||
package org.bspeice.minimalbible.activity.viewer
 | 
			
		||||
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.annotation.LayoutRes
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.BaseExpandableListAdapter
 | 
			
		||||
import org.bspeice.minimalbible.R
 | 
			
		||||
import org.crosswire.jsword.book.Book
 | 
			
		||||
import org.crosswire.jsword.book.bookName
 | 
			
		||||
import org.crosswire.jsword.book.getVersification
 | 
			
		||||
import org.crosswire.jsword.versification.BibleBook
 | 
			
		||||
import org.crosswire.jsword.versification.getBooks
 | 
			
		||||
import rx.subjects.PublishSubject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * The actual adapter for displaying a book's menu navigation system.
 | 
			
		||||
 * There are a couple of notes about this:
 | 
			
		||||
 *  Books are displayed with one row per BibleBook (Genesis, Exodus, etc.) as the group.
 | 
			
		||||
 *  Within each group, there are 3 chapters listed per row (to save space). In order to
 | 
			
		||||
 *  accommodate this, some slightly funky mathematics have to be used, and this is documented.
 | 
			
		||||
 *  Additionally, it doesn't make a whole lot of sense to genericize this using constants
 | 
			
		||||
 *  unless we go to programmatic layouts, since we still need to know the view ID's ahead of time.
 | 
			
		||||
 *
 | 
			
		||||
 * TODO: Refactor this so the math parts are separate from the actual override functions,
 | 
			
		||||
 * so it's easier to test.
 | 
			
		||||
 */
 | 
			
		||||
class BibleMenuAdapter(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))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getGroupIdForBook(b: BibleBook) = menuMappings.indexOf(
 | 
			
		||||
            menuMappings.first { it.first == b }
 | 
			
		||||
    )
 | 
			
		||||
 | 
			
		||||
    var groupHighlighted: Int = 0
 | 
			
		||||
 | 
			
		||||
    override fun getGroupCount(): Int = menuMappings.count()
 | 
			
		||||
 | 
			
		||||
    fun getChaptersForGroup(group: Int) = menuMappings[group].second
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the number of child views for a given book.
 | 
			
		||||
     * What makes this complicated is that we display 3 chapters per row.
 | 
			
		||||
     * To make sure we include everything and account for integer division,
 | 
			
		||||
     * we have to add a row if the chapter count modulo 3 is not even.
 | 
			
		||||
     */
 | 
			
		||||
    override fun getChildrenCount(group: Int): Int {
 | 
			
		||||
        val chapterCount = getChaptersForGroup(group)
 | 
			
		||||
        return when (chapterCount % 3) {
 | 
			
		||||
            0 -> chapterCount / 3
 | 
			
		||||
            else -> (chapterCount / 3) + 1
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getGroup(group: Int): String = b.bookName(menuMappings[group].first)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the starting chapter number for this child view
 | 
			
		||||
     * In order to account for displaying 3 chapters per line,
 | 
			
		||||
     * we need to multiply by three, and then add 1 for the index offset
 | 
			
		||||
     */
 | 
			
		||||
    override fun getChild(group: Int, child: Int): Int = (child * 3) + 1
 | 
			
		||||
 | 
			
		||||
    override fun getGroupId(group: Int): Long = group.toLong()
 | 
			
		||||
 | 
			
		||||
    override fun getChildId(group: Int, child: Int): Long = child.toLong()
 | 
			
		||||
 | 
			
		||||
    override fun hasStableIds(): Boolean = true
 | 
			
		||||
 | 
			
		||||
    override fun isChildSelectable(group: Int, child: Int): Boolean = true
 | 
			
		||||
 | 
			
		||||
    override fun getGroupView(position: Int, expanded: Boolean,
 | 
			
		||||
                              convertView: View?, parent: ViewGroup): View =
 | 
			
		||||
            BibleMenuGroup.init(
 | 
			
		||||
                    getOrInflate(convertView, parent, R.layout.list_bible_menu_group),
 | 
			
		||||
                    getGroup(position),
 | 
			
		||||
                    position == groupHighlighted)
 | 
			
		||||
 | 
			
		||||
    override fun getChildView(group: Int, child: Int, isLast: Boolean,
 | 
			
		||||
                              convertView: View?, parent: ViewGroup): View {
 | 
			
		||||
        val chapterStart = getChild(group, child)
 | 
			
		||||
        val chapterCount = getChaptersForGroup(group)
 | 
			
		||||
        val chapterEnd =
 | 
			
		||||
                if (chapterCount < chapterStart + 2)
 | 
			
		||||
                    chapterCount
 | 
			
		||||
                else
 | 
			
		||||
                    chapterStart + 2
 | 
			
		||||
        val view = BibleMenuChild.init(
 | 
			
		||||
                getOrInflate(convertView, parent, R.layout.list_bible_menu_child),
 | 
			
		||||
                chapterStart..chapterEnd,
 | 
			
		||||
                menuMappings[group].first,
 | 
			
		||||
                scrollPublisher
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return view
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun getOrInflate(v: View?, p: ViewGroup, LayoutRes layout: Int) =
 | 
			
		||||
            v ?: (p.getContext()
 | 
			
		||||
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
 | 
			
		||||
                    .inflate(layout, p, false)
 | 
			
		||||
}
 | 
			
		||||
@ -3,22 +3,12 @@ package org.bspeice.minimalbible.activity.viewer
 | 
			
		||||
import android.content.Context
 | 
			
		||||
import android.support.v7.widget.LinearLayoutManager
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.text.SpannableStringBuilder
 | 
			
		||||
import android.util.AttributeSet
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.util.TypedValue
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.View
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.LinearLayout
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import org.bspeice.minimalbible.R
 | 
			
		||||
import org.bspeice.minimalbible.activity.viewer.BookAdapter.ChapterInfo
 | 
			
		||||
import org.bspeice.minimalbible.service.format.osisparser.OsisParser
 | 
			
		||||
import org.crosswire.jsword.book.Book
 | 
			
		||||
import org.crosswire.jsword.book.getVersification
 | 
			
		||||
import org.crosswire.jsword.versification.BibleBook
 | 
			
		||||
import org.crosswire.jsword.versification.getBooks
 | 
			
		||||
import rx.subjects.PublishSubject
 | 
			
		||||
 | 
			
		||||
class BibleView(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, attrs) {
 | 
			
		||||
@ -41,117 +31,3 @@ class BibleView(val ctx: Context, val attrs: AttributeSet) : LinearLayout(ctx, a
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapter used for displaying a book
 | 
			
		||||
 * Displays one chapter at a time,
 | 
			
		||||
 * as each TextView widget is it's own line break
 | 
			
		||||
 */
 | 
			
		||||
class BookAdapter(val b: Book, val prefs: BibleViewerPreferences)
 | 
			
		||||
: RecyclerView.Adapter<PassageView>() {
 | 
			
		||||
 | 
			
		||||
    val versification = b.getVersification()
 | 
			
		||||
    val bookList = versification.getBooks()
 | 
			
		||||
    //    val chapterCount = bookList.map { versification.getLastChapter(it) - 1 }.sum()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Store information needed to decode the text of a chapter
 | 
			
		||||
     * Book, chapter, and bibleBook should be pretty self-explanatory
 | 
			
		||||
     * The vStart, vEnd, and vOffset are needed to map between verses relative to their chapter,
 | 
			
		||||
     * and the actual verse ordinal needed for parsing the text.
 | 
			
		||||
     * So Genesis 1:1 would be chapter 1, bibleBook Genesis, vStart 1, vOffset 2
 | 
			
		||||
     * since it actually starts at ordinal 3
 | 
			
		||||
     */
 | 
			
		||||
    data class ChapterInfo(val book: Book, val chapter: Int, val bibleBook: BibleBook,
 | 
			
		||||
                           val vStart: Int, val vEnd: Int, val vOffset: Int)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A list of all ChapterInfo objects needed for displaying a book
 | 
			
		||||
     * The for expression probably looks a bit nicer:
 | 
			
		||||
     *  for {
 | 
			
		||||
     *      book <- bookList
 | 
			
		||||
     *      chapter <- 1..versification.getLastChapter(currentBook)
 | 
			
		||||
     *  } yield ChapterInfo(...)
 | 
			
		||||
     *
 | 
			
		||||
     *  Also note that getLastVerse() returns the number of verses in a chapter,
 | 
			
		||||
     *  not the actual last verse's ordinal
 | 
			
		||||
     */
 | 
			
		||||
    // TODO: Lazy compute values needed for this list
 | 
			
		||||
    val chapterList: List<ChapterInfo> = bookList.flatMap {
 | 
			
		||||
        val currentBook = it
 | 
			
		||||
        (1..versification.getLastChapter(currentBook)).map {
 | 
			
		||||
            val firstVerseOrdinal = versification.getFirstVerse(currentBook, it)
 | 
			
		||||
            val verseOrdinalOffset = firstVerseOrdinal - 1
 | 
			
		||||
            val verseCount = versification.getLastVerse(currentBook, it)
 | 
			
		||||
            val firstVerseRelative = 1
 | 
			
		||||
            val lastVerseRelative = firstVerseRelative + verseCount
 | 
			
		||||
 | 
			
		||||
            ChapterInfo(b, it, currentBook,
 | 
			
		||||
                    firstVerseRelative, lastVerseRelative, verseOrdinalOffset)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * I'm not sure what the position argument actually represents,
 | 
			
		||||
     * but on initial load it doesn't change
 | 
			
		||||
     */
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup?,
 | 
			
		||||
                                    position: Int): PassageView {
 | 
			
		||||
        val emptyView = LayoutInflater.from(parent!!.getContext())
 | 
			
		||||
                .inflate(R.layout.viewer_passage_view, parent, false) as TextView
 | 
			
		||||
 | 
			
		||||
        // TODO: Listen for changes to the text size?
 | 
			
		||||
        emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, prefs.baseTextSize().toFloat())
 | 
			
		||||
 | 
			
		||||
        val passage = PassageView(emptyView, b)
 | 
			
		||||
        return passage
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Bind an existing view to its chapter content
 | 
			
		||||
     */
 | 
			
		||||
    override fun onBindViewHolder(view: PassageView, position: Int) {
 | 
			
		||||
        prefs.currentChapter(position)
 | 
			
		||||
        return view bind chapterList[position]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the number of chapters in the book
 | 
			
		||||
     */
 | 
			
		||||
    override fun getItemCount(): Int = chapterList.size()
 | 
			
		||||
 | 
			
		||||
    public fun bindScrollHandler(provider: PublishSubject<BookScrollEvent>,
 | 
			
		||||
                                 lM: RecyclerView.LayoutManager) {
 | 
			
		||||
        provider subscribe {
 | 
			
		||||
            val event = it
 | 
			
		||||
            lM scrollToPosition
 | 
			
		||||
                    // Get all objects in the form (index, object)
 | 
			
		||||
                    chapterList.withIndex()
 | 
			
		||||
                            // get one that matches our book and chapter
 | 
			
		||||
                            .first {
 | 
			
		||||
                                event.b == it.value.bibleBook &&
 | 
			
		||||
                                        event.chapter == it.value.chapter
 | 
			
		||||
                            }
 | 
			
		||||
                            // and get that index value to scroll to
 | 
			
		||||
                            .index
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PassageView(val v: TextView, val b: Book)
 | 
			
		||||
: RecyclerView.ViewHolder(v) {
 | 
			
		||||
 | 
			
		||||
    fun buildOrdinal(verse: Int, info: ChapterInfo) =
 | 
			
		||||
            b.getVersification().decodeOrdinal(verse + info.vOffset)
 | 
			
		||||
 | 
			
		||||
    fun getAllVerses(verses: Progression<Int>, info: ChapterInfo): SpannableStringBuilder {
 | 
			
		||||
        val builder = SpannableStringBuilder()
 | 
			
		||||
        val parser = OsisParser()
 | 
			
		||||
        verses.forEach { parser.appendVerse(b, buildOrdinal(it, info), builder) }
 | 
			
		||||
        return builder
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun bind(info: ChapterInfo) {
 | 
			
		||||
        Log.d("PassageView", "Binding chapter ${info.chapter}")
 | 
			
		||||
        v setText getAllVerses(info.vStart..info.vEnd, info)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,109 @@
 | 
			
		||||
package org.bspeice.minimalbible.activity.viewer
 | 
			
		||||
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.util.TypedValue
 | 
			
		||||
import android.view.LayoutInflater
 | 
			
		||||
import android.view.ViewGroup
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import org.bspeice.minimalbible.R
 | 
			
		||||
import org.crosswire.jsword.book.Book
 | 
			
		||||
import org.crosswire.jsword.book.getVersification
 | 
			
		||||
import org.crosswire.jsword.versification.BibleBook
 | 
			
		||||
import org.crosswire.jsword.versification.getBooks
 | 
			
		||||
import rx.subjects.PublishSubject
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Adapter used for displaying a book
 | 
			
		||||
 * Displays one chapter at a time,
 | 
			
		||||
 * as each TextView widget is it's own line break
 | 
			
		||||
 */
 | 
			
		||||
class BookAdapter(val b: Book, val prefs: BibleViewerPreferences)
 | 
			
		||||
: RecyclerView.Adapter<PassageView>() {
 | 
			
		||||
 | 
			
		||||
    val versification = b.getVersification()
 | 
			
		||||
    val bookList = versification.getBooks()
 | 
			
		||||
    //    val chapterCount = bookList.map { versification.getLastChapter(it) - 1 }.sum()
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Store information needed to decode the text of a chapter
 | 
			
		||||
     * Book, chapter, and bibleBook should be pretty self-explanatory
 | 
			
		||||
     * The vStart, vEnd, and vOffset are needed to map between verses relative to their chapter,
 | 
			
		||||
     * and the actual verse ordinal needed for parsing the text.
 | 
			
		||||
     * So Genesis 1:1 would be chapter 1, bibleBook Genesis, vStart 1, vOffset 2
 | 
			
		||||
     * since it actually starts at ordinal 3
 | 
			
		||||
     */
 | 
			
		||||
    data class ChapterInfo(val book: Book, val chapter: Int, val bibleBook: BibleBook,
 | 
			
		||||
                           val vStart: Int, val vEnd: Int, val vOffset: Int)
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * A list of all ChapterInfo objects needed for displaying a book
 | 
			
		||||
     * The for expression probably looks a bit nicer:
 | 
			
		||||
     *  for {
 | 
			
		||||
     *      book <- bookList
 | 
			
		||||
     *      chapter <- 1..versification.getLastChapter(currentBook)
 | 
			
		||||
     *  } yield ChapterInfo(...)
 | 
			
		||||
     *
 | 
			
		||||
     *  Also note that getLastVerse() returns the number of verses in a chapter,
 | 
			
		||||
     *  not the actual last verse's ordinal
 | 
			
		||||
     */
 | 
			
		||||
    // TODO: Lazy compute values needed for this list
 | 
			
		||||
    val chapterList: List<ChapterInfo> = bookList.flatMap {
 | 
			
		||||
        val currentBook = it
 | 
			
		||||
        (1..versification.getLastChapter(currentBook)).map {
 | 
			
		||||
            val firstVerseOrdinal = versification.getFirstVerse(currentBook, it)
 | 
			
		||||
            val verseOrdinalOffset = firstVerseOrdinal - 1
 | 
			
		||||
            val verseCount = versification.getLastVerse(currentBook, it)
 | 
			
		||||
            val firstVerseRelative = 1
 | 
			
		||||
            val lastVerseRelative = firstVerseRelative + verseCount
 | 
			
		||||
 | 
			
		||||
            ChapterInfo(b, it, currentBook,
 | 
			
		||||
                    firstVerseRelative, lastVerseRelative, verseOrdinalOffset)
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * I'm not sure what the position argument actually represents,
 | 
			
		||||
     * but on initial load it doesn't change
 | 
			
		||||
     */
 | 
			
		||||
    override fun onCreateViewHolder(parent: ViewGroup?,
 | 
			
		||||
                                    position: Int): PassageView {
 | 
			
		||||
        val emptyView = LayoutInflater.from(parent!!.getContext())
 | 
			
		||||
                .inflate(R.layout.viewer_passage_view, parent, false) as TextView
 | 
			
		||||
 | 
			
		||||
        // TODO: Listen for changes to the text size?
 | 
			
		||||
        emptyView.setTextSize(TypedValue.COMPLEX_UNIT_SP, prefs.baseTextSize().toFloat())
 | 
			
		||||
 | 
			
		||||
        val passage = PassageView(emptyView, b)
 | 
			
		||||
        return passage
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Bind an existing view to its chapter content
 | 
			
		||||
     */
 | 
			
		||||
    override fun onBindViewHolder(view: PassageView, position: Int) {
 | 
			
		||||
        prefs.currentChapter(position)
 | 
			
		||||
        return view bind chapterList[position]
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Get the number of chapters in the book
 | 
			
		||||
     */
 | 
			
		||||
    override fun getItemCount(): Int = chapterList.size()
 | 
			
		||||
 | 
			
		||||
    public fun bindScrollHandler(provider: PublishSubject<BookScrollEvent>,
 | 
			
		||||
                                 lM: RecyclerView.LayoutManager) {
 | 
			
		||||
        provider subscribe {
 | 
			
		||||
            val event = it
 | 
			
		||||
            lM scrollToPosition
 | 
			
		||||
                    // Get all objects in the form (index, object)
 | 
			
		||||
                    chapterList.withIndex()
 | 
			
		||||
                            // get one that matches our book and chapter
 | 
			
		||||
                            .first {
 | 
			
		||||
                                event.b == it.value.bibleBook &&
 | 
			
		||||
                                        event.chapter == it.value.chapter
 | 
			
		||||
                            }
 | 
			
		||||
                            // and get that index value to scroll to
 | 
			
		||||
                            .index
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -0,0 +1,28 @@
 | 
			
		||||
package org.bspeice.minimalbible.activity.viewer
 | 
			
		||||
 | 
			
		||||
import android.support.v7.widget.RecyclerView
 | 
			
		||||
import android.text.SpannableStringBuilder
 | 
			
		||||
import android.util.Log
 | 
			
		||||
import android.widget.TextView
 | 
			
		||||
import org.bspeice.minimalbible.service.format.osisparser.OsisParser
 | 
			
		||||
import org.crosswire.jsword.book.Book
 | 
			
		||||
import org.crosswire.jsword.book.getVersification
 | 
			
		||||
 | 
			
		||||
class PassageView(val v: TextView, val b: Book)
 | 
			
		||||
: RecyclerView.ViewHolder(v) {
 | 
			
		||||
 | 
			
		||||
    fun buildOrdinal(verse: Int, info: BookAdapter.ChapterInfo) =
 | 
			
		||||
            b.getVersification().decodeOrdinal(verse + info.vOffset)
 | 
			
		||||
 | 
			
		||||
    fun getAllVerses(verses: Progression<Int>, info: BookAdapter.ChapterInfo): SpannableStringBuilder {
 | 
			
		||||
        val builder = SpannableStringBuilder()
 | 
			
		||||
        val parser = OsisParser()
 | 
			
		||||
        verses.forEach { parser.appendVerse(b, buildOrdinal(it, info), builder) }
 | 
			
		||||
        return builder
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun bind(info: BookAdapter.ChapterInfo) {
 | 
			
		||||
        Log.d("PassageView", "Binding chapter ${info.chapter}")
 | 
			
		||||
        v setText getAllVerses(info.vStart..info.vEnd, info)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user