mirror of
https://github.com/MinimalBible/MinimalBible
synced 2024-12-22 14:48:23 -05:00
Kotlin migration is done!
There will of course be refactoring and whatnot, but I consider this an accomplishment.
This commit is contained in:
parent
0e7680ca9e
commit
187a73cf92
@ -2,7 +2,8 @@ package org.bspeice.minimalbible.activity.viewer;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import org.bspeice.minimalbible.service.book.VerseLookupModules;
|
||||
import org.bspeice.minimalbible.service.lookup.DefaultVerseLookup;
|
||||
import org.bspeice.minimalbible.service.lookup.VerseLookup;
|
||||
import org.bspeice.minimalbible.service.manager.BookManager;
|
||||
import org.crosswire.jsword.book.Book;
|
||||
|
||||
@ -26,8 +27,7 @@ import rx.functions.Func1;
|
||||
BibleViewer.class,
|
||||
BookFragment.class,
|
||||
BookChapterNavFragment.class
|
||||
},
|
||||
includes = VerseLookupModules.class
|
||||
}
|
||||
)
|
||||
@SuppressWarnings("unused")
|
||||
public class BibleViewerModules {
|
||||
@ -96,4 +96,10 @@ public class BibleViewerModules {
|
||||
BookManager bookManager() {
|
||||
return new BookManager();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
VerseLookup verseLookup(@Named("MainBook") Book b) {
|
||||
return new DefaultVerseLookup(b);
|
||||
}
|
||||
}
|
@ -12,7 +12,7 @@ import android.webkit.WebView;
|
||||
import org.bspeice.minimalbible.Injector;
|
||||
import org.bspeice.minimalbible.R;
|
||||
import org.bspeice.minimalbible.activity.BaseFragment;
|
||||
import org.bspeice.minimalbible.service.book.VerseLookupService;
|
||||
import org.bspeice.minimalbible.service.lookup.VerseLookup;
|
||||
import org.crosswire.jsword.book.Book;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@ -20,7 +20,6 @@ import javax.inject.Named;
|
||||
|
||||
import butterknife.ButterKnife;
|
||||
import butterknife.InjectView;
|
||||
import dagger.Lazy;
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.functions.Action1;
|
||||
import rx.subjects.PublishSubject;
|
||||
@ -35,18 +34,15 @@ public class BookFragment extends BaseFragment {
|
||||
Injector i;
|
||||
@Inject
|
||||
@Named("MainBook")
|
||||
Lazy<Book> mBook;
|
||||
Book mBook;
|
||||
@Inject
|
||||
VerseLookup verseLookup;
|
||||
|
||||
@InjectView(R.id.book_content)
|
||||
WebView mainContent;
|
||||
|
||||
PublishSubject<String> titleReceiver = PublishSubject.create();
|
||||
|
||||
public BookFragment() {
|
||||
// We can't initialize the lookupService here since the fragment hasn't been tied
|
||||
// to the parent activity yet.
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new instance of this fragment for the given book.
|
||||
*/
|
||||
@ -76,7 +72,7 @@ public class BookFragment extends BaseFragment {
|
||||
|
||||
// TODO: Load initial text from SharedPreferences, rather than getting the actual book.
|
||||
|
||||
displayBook(mBook.get());
|
||||
displayBook(mBook);
|
||||
|
||||
return rootView;
|
||||
}
|
||||
@ -103,8 +99,7 @@ public class BookFragment extends BaseFragment {
|
||||
((BibleViewer)getActivity()).setActionBarTitle(b.getInitials());
|
||||
mainContent.loadUrl(getString(R.string.book_html));
|
||||
|
||||
VerseLookupService lookupService = new VerseLookupService(i, mBook.get());
|
||||
BibleViewClient client = new BibleViewClient(b, lookupService, titleReceiver);
|
||||
BibleViewClient client = new BibleViewClient(b, verseLookup, titleReceiver);
|
||||
titleReceiver
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Action1<String>() {
|
||||
|
@ -1,7 +0,0 @@
|
||||
package org.bspeice.minimalbible.exception;
|
||||
|
||||
/**
|
||||
* Error to be thrown when no books are currently installed.
|
||||
*/
|
||||
public class NoBooksInstalledException extends Exception {
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package org.bspeice.minimalbible.service.book;
|
||||
|
||||
import android.support.v4.util.LruCache;
|
||||
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
|
||||
/**
|
||||
* Created by bspeice on 9/1/14.
|
||||
*/
|
||||
@Module(injects = VerseLookupService.class)
|
||||
public class VerseLookupModules {
|
||||
private static final int MAX_SIZE = 1000000; // 1MB
|
||||
|
||||
/**
|
||||
* Create a new LruCache. We're free to create new ones since they're all backed by the file
|
||||
* system anyways.
|
||||
*
|
||||
* @return The LruCache to use
|
||||
*/
|
||||
@Provides
|
||||
LruCache<String, String> getLruCache() {
|
||||
return new LruCache<String, String>(MAX_SIZE);
|
||||
}
|
||||
}
|
@ -1,148 +0,0 @@
|
||||
package org.bspeice.minimalbible.service.book;
|
||||
|
||||
import android.support.v4.util.LruCache;
|
||||
|
||||
import org.bspeice.minimalbible.Injector;
|
||||
import org.bspeice.minimalbible.service.format.osisparser.OsisParser;
|
||||
import org.crosswire.common.xml.SAXEventProvider;
|
||||
import org.crosswire.jsword.book.Book;
|
||||
import org.crosswire.jsword.book.BookData;
|
||||
import org.crosswire.jsword.book.BookException;
|
||||
import org.crosswire.jsword.passage.Verse;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import rx.functions.Action1;
|
||||
import rx.schedulers.Schedulers;
|
||||
import rx.subjects.PublishSubject;
|
||||
|
||||
/**
|
||||
* This class has a simple purpose, but implements the dirty work needed to make it happen.
|
||||
* The idea is this: someone wants the text for a verse, we look it up quickly.
|
||||
* This means aggressive caching, cache prediction, and classes letting us know that some verses
|
||||
* may be needed in the future (i.e. searching).
|
||||
* <p/>
|
||||
* There is one VerseLookupService per Book, but multiple VerseLookupServices can work with
|
||||
* the same book. Because the actual caching mechanism is disk-based, we're safe.
|
||||
* <p/>
|
||||
* TODO: Statistics on cache hits/misses vs. verses cached
|
||||
*/
|
||||
public class VerseLookupService implements Action1<Verse> {
|
||||
|
||||
Book book;
|
||||
|
||||
@Inject
|
||||
LruCache<String, String> cache;
|
||||
/**
|
||||
* The listener is responsible for delegating calls to cache verses.
|
||||
* This way, @notifyVerse can just tell the listener what's what,
|
||||
* and the listener can delegate to another thread.
|
||||
*/
|
||||
private PublishSubject<Verse> listener = PublishSubject.create();
|
||||
|
||||
public VerseLookupService(Injector i, Book b) {
|
||||
listener.subscribeOn(Schedulers.io())
|
||||
.subscribe(this);
|
||||
this.book = b;
|
||||
i.inject(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the text for a corresponding verse
|
||||
* First, check the cache. If that doesn't exist, manually get the verse.
|
||||
* In all cases, notify that we're looking up a verse so we can get the surrounding ones.
|
||||
*
|
||||
* @param v The verse to look up
|
||||
* @return The JSON object for this verse (\<p\/>)
|
||||
*/
|
||||
public String getJsonVerse(Verse v) {
|
||||
if (contains(v)) {
|
||||
return cache.get(getEntryName(v));
|
||||
} else {
|
||||
// The awkward method calls below are so notifyVerse doesn't
|
||||
// call the same doVerseLookup
|
||||
String verseContent = doVerseLookup(v);
|
||||
notifyVerse(v);
|
||||
return verseContent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the ugly work of getting the actual data for a verse
|
||||
* Note that we build the verse object, JS should be left to determine how
|
||||
* it is displayed.
|
||||
*
|
||||
* @param v The verse to look up
|
||||
* @return The JSON content of this verse
|
||||
*/
|
||||
public String doVerseLookup(Verse v) {
|
||||
BookData bookData = new BookData(book, v);
|
||||
try {
|
||||
SAXEventProvider provider = bookData.getSAXEventProvider();
|
||||
OsisParser handler = new OsisParser();
|
||||
handler.setVerse(v);
|
||||
provider.provideSAXEvents(handler);
|
||||
return handler.getVerseContent().toJson();
|
||||
} catch (BookException e) {
|
||||
e.printStackTrace();
|
||||
return "Unable to locate " + v.toString() + "!";
|
||||
} catch (SAXException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Not necessary, but helpful if you let us know ahead of time we should pre-cache a verse.
|
||||
* For example, if something showed up in search results, it'd be helpful to start
|
||||
* looking up some of the results.
|
||||
*
|
||||
* @param v The verse we should pre-cache
|
||||
*/
|
||||
public void notifyVerse(Verse v) {
|
||||
listener.onNext(v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Let someone know if the cache contains a verse we want
|
||||
* Also provides a nice wrapper if the underlying cache isn't working properly.
|
||||
*
|
||||
* @param v The verse to check
|
||||
* @return Whether we can retrieve the verse from our cache
|
||||
*/
|
||||
public boolean contains(Verse v) {
|
||||
return cache.get(getEntryName(v)) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a verse, what should it's name in the cache be?
|
||||
* Example: Matthew 7:7 becomes:
|
||||
* MAT_7_7
|
||||
*
|
||||
* @param v The verse we need to generate a name for
|
||||
* @return The name this verse should have in the cache
|
||||
*/
|
||||
private String getEntryName(Verse v) {
|
||||
return v.getBook().toString() + "_" +
|
||||
v.getChapter() + "_" +
|
||||
v.getVerse();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------------
|
||||
IO Thread operations below
|
||||
------------------------------------------------------------------------*/
|
||||
|
||||
/**
|
||||
* The listener has let us know that we need to look up a verse. So, look up
|
||||
* that one first, and get its surrounding verses as well just in case.
|
||||
* We can safely assume we are not on the main thread.
|
||||
*
|
||||
* @param verse The verse we need to look up
|
||||
*/
|
||||
|
||||
@Override
|
||||
public void call(Verse verse) {
|
||||
|
||||
}
|
||||
}
|
@ -1,35 +1,34 @@
|
||||
package org.bspeice.minimalbible.activity.viewer
|
||||
|
||||
import org.crosswire.jsword.passage.Verse
|
||||
import org.bspeice.minimalbible.service.book.VerseLookupService
|
||||
import android.webkit.WebViewClient
|
||||
import android.webkit.JavascriptInterface
|
||||
import org.crosswire.jsword.book.Book
|
||||
import java.util.ArrayList
|
||||
import android.util.Log
|
||||
import rx.subjects.PublishSubject
|
||||
import org.crosswire.jsword.book.getVersification
|
||||
import org.bspeice.minimalbible.service.lookup.VerseLookup
|
||||
|
||||
/**
|
||||
* Created by bspeice on 9/14/14.
|
||||
*/
|
||||
|
||||
class BibleViewClient(val b: Book, val lookup: VerseLookupService,
|
||||
class BibleViewClient(val b: Book, val lookup: VerseLookup,
|
||||
val subject: PublishSubject<String>?) : WebViewClient() {
|
||||
|
||||
// We can receive and return only primitives and Strings. Still means we can use JSON :)
|
||||
JavascriptInterface fun getVerse(ordinal: Int): String {
|
||||
val v = Verse(b.getVersification(), ordinal)
|
||||
// TODO: WebView should notify us what verse it's on
|
||||
subject?.onNext(v.getBook().toString() + " " + v.getChapter() + ":" + v.getVerse())
|
||||
return lookup.getJsonVerse(v)
|
||||
subject?.onNext("${v.getBook()} ${v.getChapter()}:${v.getVerse()}")
|
||||
return lookup getJson v
|
||||
}
|
||||
|
||||
JavascriptInterface fun getVerses(first: Int, count: Int): String {
|
||||
Log.e("getVerses", "First: " + first + " count: " + count)
|
||||
val verses: MutableList<String> = ArrayList<String>()
|
||||
var trueCount: Int
|
||||
var trueFirst: Int
|
||||
Log.e("getVerses", "First: $first count: $count")
|
||||
val verses: MutableList<String> = linkedListOf()
|
||||
val trueCount: Int
|
||||
val trueFirst: Int
|
||||
when {
|
||||
first < 0 - count -> return ""
|
||||
first < 0 -> {
|
||||
@ -45,7 +44,7 @@ class BibleViewClient(val b: Book, val lookup: VerseLookupService,
|
||||
for (i in trueFirst..trueFirst + trueCount - 1) {
|
||||
verses.add(getVerse(i))
|
||||
}
|
||||
Log.e("getVerses", "return verses size: " + verses.size.toString())
|
||||
Log.e("getVerses", "return verses size: ${verses.size}")
|
||||
return verses.toString()
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
package org.bspeice.minimalbible.exception
|
||||
|
||||
class NoBooksInstalledException() : Exception("No books currently installed!") {}
|
@ -22,6 +22,8 @@ class OsisParser() : DefaultHandler() {
|
||||
// TODO: Implement a stack to keep min API 8
|
||||
val doWrite = ArrayDeque<Boolean>()
|
||||
|
||||
fun getJson() = verseContent.toJson()
|
||||
|
||||
override fun startElement(uri: String, localName: String,
|
||||
qName: String, attributes: Attributes) {
|
||||
when (localName) {
|
||||
|
@ -0,0 +1,84 @@
|
||||
package org.bspeice.minimalbible.service.lookup
|
||||
|
||||
import org.crosswire.jsword.book.Book
|
||||
import android.support.v4.util.LruCache
|
||||
import rx.functions.Action1
|
||||
import org.crosswire.jsword.passage.Verse
|
||||
import rx.subjects.PublishSubject
|
||||
import rx.schedulers.Schedulers
|
||||
import org.crosswire.jsword.book.BookData
|
||||
import org.bspeice.minimalbible.service.format.osisparser.OsisParser
|
||||
|
||||
/**
|
||||
* Created by bspeice on 11/12/14.
|
||||
*/
|
||||
open class VerseLookup(val b: Book,
|
||||
val cache: LruCache<Int, String> = LruCache(1000000)) : Action1<Verse> {
|
||||
/**
|
||||
* The listener servers to let other objects notify us we should pre-cache verses
|
||||
*/
|
||||
val listener: PublishSubject<Verse> = PublishSubject.create();
|
||||
|
||||
{
|
||||
listener.observeOn(Schedulers.io())
|
||||
.subscribe(this)
|
||||
}
|
||||
|
||||
fun getVerseId(v: Verse) = v.getOrdinal()
|
||||
|
||||
fun getJson(v: Verse): String =
|
||||
if (contains(v))
|
||||
cache[getVerseId(v)]
|
||||
else {
|
||||
val content = doLookup(v)
|
||||
notify(v)
|
||||
content
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform the ugly work of getting the actual data for a verse
|
||||
* Note that we build the verse object, JS should be left to determine how
|
||||
* it is displayed.
|
||||
*
|
||||
* @param v The verse to look up
|
||||
* @return The JSON content of this verse
|
||||
*/
|
||||
fun doLookup(v: Verse): String {
|
||||
val data = BookData(b, v)
|
||||
val provider = data.getSAXEventProvider()
|
||||
val handler = OsisParser()
|
||||
handler.verse = v
|
||||
provider provideSAXEvents handler
|
||||
return handler.getJson()
|
||||
}
|
||||
|
||||
/**
|
||||
* Not necessary, but helpful if you let us know ahead of time we should pre-cache a verse.
|
||||
* For example, if something showed up in search results, it'd be helpful to start
|
||||
* looking up some of the results.
|
||||
*
|
||||
* @param v The verse we should pre-cache
|
||||
*/
|
||||
fun notify(v: Verse) = listener onNext v
|
||||
|
||||
/**
|
||||
* Let someone know if the cache contains a verse we want
|
||||
* Also provides a nice wrapper if the underlying cache isn't working properly.
|
||||
*
|
||||
* @param v The verse to check
|
||||
* @return Whether we can retrieve the verse from our cache
|
||||
*/
|
||||
fun contains(v: Verse) = cache[v.getOrdinal()] != null
|
||||
|
||||
// IO Thread operations begin here
|
||||
|
||||
/**
|
||||
* Someone was nice enough to let us know that a verse was recently called,
|
||||
* we should probably cache its neighbors!
|
||||
*/
|
||||
override fun call(t1: Verse?) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultVerseLookup(b: Book) : VerseLookup(b) {}
|
Loading…
Reference in New Issue
Block a user