RefreshManager going functional!

This commit is contained in:
Bradlee Speice 2014-10-22 22:21:42 -04:00
parent 6d15167100
commit 22fd32b26d
13 changed files with 205 additions and 281 deletions

View File

@ -35,37 +35,6 @@ import static com.jayway.awaitility.Awaitility.await;
public class BookDownloadManagerTest extends TestCase implements Injector { public class BookDownloadManagerTest extends TestCase implements Injector {
ObjectGraph mObjectGraph; ObjectGraph mObjectGraph;
/**
* Modules needed for this test case
*/
@Module(injects = {BookDownloadManager.class,
RefreshManager.class,
BookDownloadManagerTest.class})
public static class BookDownloadManagerTestModules {
Injector i;
BookDownloadManagerTestModules(Injector i) {
this.i = i;
}
@Provides
@Singleton
Injector provideInjector() {
return i;
}
@Provides @Singleton
Books provideBooks() {
return Books.installed();
}
@Provides @Singleton
Collection<Installer> provideInstallers() {
return new InstallManager().getInstallers().values();
}
}
@Inject BookDownloadManager bookDownloadManager; @Inject BookDownloadManager bookDownloadManager;
@Inject RefreshManager refreshManager; @Inject RefreshManager refreshManager;
@Inject Books installedBooks; @Inject Books installedBooks;
@ -82,7 +51,7 @@ public class BookDownloadManagerTest extends TestCase implements Injector {
} }
Observable<Book> installableBooks() { Observable<Book> installableBooks() {
return refreshManager.getAvailableModulesFlattened() return refreshManager.getAvailableModulesFlat()
.filter(new Func1<Book, Boolean>() { .filter(new Func1<Book, Boolean>() {
@Override @Override
public Boolean call(Book book) { public Boolean call(Book book) {
@ -135,4 +104,43 @@ public class BookDownloadManagerTest extends TestCase implements Injector {
await().atMost(1, TimeUnit.SECONDS) await().atMost(1, TimeUnit.SECONDS)
.untilTrue(jobNameMatch); .untilTrue(jobNameMatch);
} }
/**
* Modules needed for this test case
*/
@Module(injects = {BookDownloadManager.class,
RefreshManager.class,
BookDownloadManagerTest.class})
@SuppressWarnings("unused")
public static class BookDownloadManagerTestModules {
Injector i;
BookDownloadManagerTestModules(Injector i) {
this.i = i;
}
@Provides
@Singleton
Injector provideInjector() {
return i;
}
@Provides
@Singleton
Books provideBooks() {
return Books.installed();
}
@Provides
@Singleton
Collection<Installer> provideInstallers() {
return new InstallManager().getInstallers().values();
}
@Provides
@Singleton
RefreshManager refreshManager(Collection<Installer> installers) {
return new RefreshManager(installers);
}
}
} }

View File

@ -36,40 +36,10 @@ import rx.functions.Func1;
*/ */
public class InstalledManagerTest extends TestCase implements Injector { public class InstalledManagerTest extends TestCase implements Injector {
ObjectGraph mObjectGraph; ObjectGraph mObjectGraph;
@Inject
@Module(injects = {InstalledManager.class, InstalledManager iM;
InstalledManagerTest.class, @Inject
RefreshManager.class, Books installedBooks;
BookDownloadManager.class})
static class IMTestModules {
Injector i;
public IMTestModules(Injector i) {
this.i = i;
}
@Provides @Singleton
Injector provideInjector() {
return this.i;
}
@Provides @Singleton
Books provideInstalledBooks() {
return Books.installed();
}
@Provides
List<Book> provideInstalledBooksList(Books b) {
return b.getBooks();
}
@Provides @Singleton
Collection<Installer> provideInstallers() {
return new InstallManager().getInstallers().values();
}
}
@Inject InstalledManager iM;
@Inject Books installedBooks;
@Override @Override
public void inject(Object o) { public void inject(Object o) {
@ -121,4 +91,46 @@ public class InstalledManagerTest extends TestCase implements Injector {
}); });
assertFalse(foundMismatch.get()); assertFalse(foundMismatch.get());
} }
@Module(injects = {InstalledManager.class,
InstalledManagerTest.class,
RefreshManager.class,
BookDownloadManager.class})
@SuppressWarnings("unused")
static class IMTestModules {
Injector i;
public IMTestModules(Injector i) {
this.i = i;
}
@Provides
@Singleton
Injector provideInjector() {
return this.i;
}
@Provides
@Singleton
Books provideInstalledBooks() {
return Books.installed();
}
@Provides
List<Book> provideInstalledBooksList(Books b) {
return b.getBooks();
}
@Provides
@Singleton
Collection<Installer> provideInstallers() {
return new InstallManager().getInstallers().values();
}
@Provides
@Singleton
RefreshManager refreshManager(Collection<Installer> installers) {
return new RefreshManager(installers);
}
}
} }

View File

@ -1,7 +1,5 @@
package org.bspeice.minimalbible.test.activity.downloader.manager; package org.bspeice.minimalbible.test.activity.downloader.manager;
import com.jayway.awaitility.Awaitility;
import junit.framework.TestCase; import junit.framework.TestCase;
import org.bspeice.minimalbible.Injector; import org.bspeice.minimalbible.Injector;
@ -26,7 +24,9 @@ import dagger.Provides;
import rx.functions.Action1; import rx.functions.Action1;
import static com.jayway.awaitility.Awaitility.await; import static com.jayway.awaitility.Awaitility.await;
import static org.mockito.Mockito.*; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
public class RefreshManagerTest extends TestCase implements Injector { public class RefreshManagerTest extends TestCase implements Injector {
@ -35,34 +35,14 @@ public class RefreshManagerTest extends TestCase implements Injector {
* for setting their own ObjectGraph. * for setting their own ObjectGraph.
*/ */
ObjectGraph mObjectGraph; ObjectGraph mObjectGraph;
@Inject
RefreshManager rM;
@Override @Override
public void inject(Object o) { public void inject(Object o) {
mObjectGraph.inject(o); mObjectGraph.inject(o);
} }
@Inject RefreshManager rM;
@Module (injects = {RefreshManagerTest.class, RefreshManager.class})
class RMTModules {
Injector i;
Collection<Installer> installers;
RMTModules(Injector i, Collection<Installer> installers) {
this.i = i;
this.installers = installers;
}
@Provides @Singleton
Injector provideInjector() {
return i;
}
@Provides @Singleton
Collection<Installer> provideInstallers() {
return this.installers;
}
}
public void testGetAvailableModulesFlattened() throws Exception { public void testGetAvailableModulesFlattened() throws Exception {
// Environment setup // Environment setup
final String mockBookName = "MockBook"; final String mockBookName = "MockBook";
@ -78,13 +58,13 @@ public class RefreshManagerTest extends TestCase implements Injector {
Collection<Installer> mockInstallers = new ArrayList<Installer>(); Collection<Installer> mockInstallers = new ArrayList<Installer>();
mockInstallers.add(mockInstaller); mockInstallers.add(mockInstaller);
RMTModules modules = new RMTModules(this, mockInstallers); RMTModules modules = new RMTModules(mockInstallers);
mObjectGraph = ObjectGraph.create(modules); mObjectGraph = ObjectGraph.create(modules);
// Now the actual test // Now the actual test
mObjectGraph.inject(this); // Get the RefreshManager mObjectGraph.inject(this); // Get the RefreshManager
rM.getAvailableModulesFlattened() rM.getAvailableModulesFlat()
.toBlocking() .toBlocking()
.forEach(new Action1<Book>() { .forEach(new Action1<Book>() {
@Override @Override
@ -109,12 +89,12 @@ public class RefreshManagerTest extends TestCase implements Injector {
Collection<Installer> mockInstallers = new ArrayList<Installer>(); Collection<Installer> mockInstallers = new ArrayList<Installer>();
mockInstallers.add(mockInstaller); mockInstallers.add(mockInstaller);
RMTModules modules = new RMTModules(this, mockInstallers); RMTModules modules = new RMTModules(mockInstallers);
mObjectGraph = ObjectGraph.create(modules); mObjectGraph = ObjectGraph.create(modules);
// And the actual test // And the actual test
mObjectGraph.inject(this); mObjectGraph.inject(this);
Installer i = rM.installerFromBook(mockBook); Installer i = rM.installerFromBook(mockBook).toBlocking().first();
assertSame(mockInstaller, i); assertSame(mockInstaller, i);
verify(mockInstaller).getBooks(); verify(mockInstaller).getBooks();
@ -127,7 +107,7 @@ public class RefreshManagerTest extends TestCase implements Injector {
@Override @Override
public List<Book> answer(InvocationOnMock invocationOnMock) throws Throwable { public List<Book> answer(InvocationOnMock invocationOnMock) throws Throwable {
Thread.sleep(1000); // Just long enough to give us a gap between Thread.sleep(1000); // Just long enough to give us a gap between
// refresh start and complete // refresh start and complete
return bookList; return bookList;
} }
}); });
@ -135,21 +115,43 @@ public class RefreshManagerTest extends TestCase implements Injector {
Collection<Installer> mockInstallers = new ArrayList<Installer>(); Collection<Installer> mockInstallers = new ArrayList<Installer>();
mockInstallers.add(mockInstaller); mockInstallers.add(mockInstaller);
RMTModules modules = new RMTModules(this, mockInstallers); RMTModules modules = new RMTModules(mockInstallers);
mObjectGraph = ObjectGraph.create(modules); mObjectGraph = ObjectGraph.create(modules);
// And the actual test // And the actual test
mObjectGraph.inject(this); mObjectGraph.inject(this);
// So the refresh should be kicked off at the constructor, meaning that it's not "complete" // So the refresh should be kicked off at the constructor, meaning that it's not "complete"
assertFalse(rM.isRefreshComplete()); assertFalse(rM.getRefreshComplete().get());
// But, if it's on another thread, it should finish up eventually, right? // But, if it's on another thread, it should finish up eventually, right?
await().atMost(5, TimeUnit.SECONDS).until(new Callable<Boolean>() { await().atMost(5, TimeUnit.SECONDS).until(new Callable<Boolean>() {
@Override @Override
public Boolean call() throws Exception { public Boolean call() throws Exception {
return rM.isRefreshComplete(); return rM.getRefreshComplete().get();
} }
}); });
} }
@Module(injects = {RefreshManagerTest.class, RefreshManager.class})
@SuppressWarnings("unused")
class RMTModules {
Collection<Installer> installers;
RMTModules(Collection<Installer> installers) {
this.installers = installers;
}
@Provides
@Singleton
Collection<Installer> provideInstallers() {
return this.installers;
}
@Provides
@Singleton
RefreshManager refreshManager(Collection<Installer> installers) {
return new RefreshManager(installers);
}
}
} }

View File

@ -18,6 +18,7 @@ import org.bspeice.minimalbible.activity.downloader.manager.RefreshManager;
import org.crosswire.jsword.book.Book; import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.BookCategory; import org.crosswire.jsword.book.BookCategory;
import org.crosswire.jsword.book.BookComparators; import org.crosswire.jsword.book.BookComparators;
import org.jetbrains.annotations.NotNull;
import java.util.List; import java.util.List;
@ -41,15 +42,12 @@ public class BookListFragment extends BaseFragment {
*/ */
protected static final String ARG_BOOK_CATEGORY = "book_category"; protected static final String ARG_BOOK_CATEGORY = "book_category";
private final String TAG = "BookListFragment"; @Inject
protected DownloadPrefs downloadPrefs;
protected ProgressDialog refreshDialog;
@InjectView(R.id.lst_download_available) @InjectView(R.id.lst_download_available)
ListView downloadsAvailable; ListView downloadsAvailable;
@Inject RefreshManager refreshManager; @Inject RefreshManager refreshManager;
@Inject protected DownloadPrefs downloadPrefs;
protected ProgressDialog refreshDialog;
private LayoutInflater inflater; private LayoutInflater inflater;
/** /**
@ -114,7 +112,7 @@ public class BookListFragment extends BaseFragment {
*/ */
private void refreshModules() { private void refreshModules() {
// Check if the downloadManager has already refreshed everything // Check if the downloadManager has already refreshed everything
if (!refreshManager.isRefreshComplete()) { if (!refreshManager.getRefreshComplete().get()) {
// downloadManager is in progress of refreshing // downloadManager is in progress of refreshing
refreshDialog = new ProgressDialog(getActivity()); refreshDialog = new ProgressDialog(getActivity());
refreshDialog.setMessage("Refreshing available modules..."); refreshDialog.setMessage("Refreshing available modules...");
@ -123,7 +121,7 @@ public class BookListFragment extends BaseFragment {
} }
// Listen for the books! // Listen for the books!
refreshManager.getAvailableModulesFlattened() refreshManager.getAvailableModulesFlat()
.filter(new Func1<Book, Boolean>() { .filter(new Func1<Book, Boolean>() {
@Override @Override
public Boolean call(Book book) { public Boolean call(Book book) {
@ -162,7 +160,7 @@ public class BookListFragment extends BaseFragment {
private class DownloadDialogListener implements private class DownloadDialogListener implements
DialogInterface.OnClickListener { DialogInterface.OnClickListener {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(@NotNull DialogInterface dialog, int which) {
downloadPrefs.hasShownDownloadDialog(true); downloadPrefs.hasShownDownloadDialog(true);
switch (which) { switch (which) {

View File

@ -40,6 +40,7 @@ import de.devland.esperandro.Esperandro;
addsTo = MinimalBibleModules.class, addsTo = MinimalBibleModules.class,
library = true library = true
) )
@SuppressWarnings("unused")
public class DownloadActivityModules { public class DownloadActivityModules {
DownloadActivity activity; DownloadActivity activity;
@ -65,7 +66,7 @@ public class DownloadActivityModules {
/** /**
* Provide the context for the DownloadActivity. We name it so that we don't have to * Provide the context for the DownloadActivity. We name it so that we don't have to
* \@Provides a specific class, but can keep track of what exactly we mean by "Context" * \@Provides a specific class, but can keep track of what exactly we mean by "Context"
* @return * @return The DownloadActivity Context
*/ */
@Provides @Singleton @Named("DownloadActivityContext") @Provides @Singleton @Named("DownloadActivityContext")
Context provideActivityContext() { Context provideActivityContext() {
@ -105,7 +106,7 @@ public class DownloadActivityModules {
} }
@Provides @Singleton @Provides @Singleton
RefreshManager provideRefreshManager() { RefreshManager provideRefreshManager(Collection<Installer> installers) {
return new RefreshManager(activity); return new RefreshManager(installers);
} }
} }

View File

@ -32,20 +32,15 @@ import rx.subjects.PublishSubject;
//TODO: Install indexes for Bibles //TODO: Install indexes for Bibles
@Singleton @Singleton
public class BookDownloadManager implements WorkListener, BooksListener { public class BookDownloadManager implements WorkListener, BooksListener {
private String TAG = "BookDownloadManager";
/** /**
* Mapping of Job ID to the EventBus we should trigger progress on * Mapping of Job ID to the EventBus we should trigger progress on
*/ */
private final Map<String, Book> bookMappings; private final Map<String, Book> bookMappings;
/** /**
* Cached copy of downloads in progress so views displaying this info can get it quickly. * Cached copy of downloads in progress so views displaying this info can get it quickly.
*/ */
private final Map<Book, DLProgressEvent> inProgressDownloads; private final Map<Book, DLProgressEvent> inProgressDownloads;
private final PublishSubject<DLProgressEvent> downloadEvents = PublishSubject.create(); private final PublishSubject<DLProgressEvent> downloadEvents = PublishSubject.create();
@Inject Books installedBooks; @Inject Books installedBooks;
@Inject RefreshManager refreshManager; @Inject RefreshManager refreshManager;
@ -58,6 +53,18 @@ public class BookDownloadManager implements WorkListener, BooksListener {
installedBooks.addBooksListener(this); installedBooks.addBooksListener(this);
} }
/**
* Build what the installer creates the job name as.
* Likely prone to be brittle.
*
* @param b The book to predict the download job name of
* @return The name of the job that will/is download/ing this book
*/
public static String getJobId(Book b) {
return "INSTALL_BOOK-" + b.getInitials();
}
public void installBook(Book b) { public void installBook(Book b) {
downloadBook(b); downloadBook(b);
addJob(getJobId(b), b); addJob(getJobId(b), b);
@ -74,32 +81,19 @@ public class BookDownloadManager implements WorkListener, BooksListener {
// First, look up where the Book came from // First, look up where the Book came from
Observable.just(refreshManager.installerFromBook(b)) Observable.just(refreshManager.installerFromBook(b))
.subscribeOn(Schedulers.io()) .subscribeOn(Schedulers.io())
.subscribe(new Action1<Installer>() { .subscribe(new Action1<Observable<Installer>>() {
@Override @Override
public void call(Installer installer) { public void call(Observable<Installer> installerObservable) {
try { try {
installer.install(b); installerObservable.toBlocking().first().install(b);
} catch (InstallException e) { } catch (InstallException e) {
Log.d(TAG, e.getMessage()); e.printStackTrace();
} }
getDownloadEvents()
.onNext(new DLProgressEvent(DLProgressEvent.PROGRESS_BEGINNING, b));
} }
}); });
}
/** getDownloadEvents()
* Build what the installer creates the job name as. .onNext(new DLProgressEvent(DLProgressEvent.PROGRESS_BEGINNING, b));
* Likely prone to be brittle.
* TODO: Make sure to test that this is an accurate job name
*
* @param b The book to predict the download job name of
* @return The name of the job that will/is download/ing this book
*/
public static String getJobId(Book b) {
return "INSTALL_BOOK-" + b.getInitials();
} }
@Override @Override

View File

@ -1,137 +0,0 @@
package org.bspeice.minimalbible.activity.downloader.manager;
import org.bspeice.minimalbible.Injector;
import org.crosswire.jsword.book.Book;
import org.crosswire.jsword.book.install.InstallException;
import org.crosswire.jsword.book.install.Installer;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
import javax.inject.Singleton;
import rx.Observable;
import rx.functions.Action0;
import rx.functions.Action1;
import rx.functions.Func1;
import rx.schedulers.Schedulers;
/**
* Handle refreshing the list of books available as needed
* Note that we don't refactor this class out since we need somewhere
* to track whether the refresh is done.
*/
@Singleton
public class RefreshManager {
/**
* Cached copy of modules that are available so we don't refresh for everyone who requests it.
*/
private Observable<Map<Installer, List<Book>>> availableModules;
private final AtomicBoolean refreshComplete = new AtomicBoolean();
@Inject
Collection<Installer> installers;
@Inject
public RefreshManager(Injector injector) {
injector.inject(this);
refreshModules();
}
/**
* Do the work of kicking off the AsyncTask to refresh books, and make sure we know
* when it's done.
* NOTE: This code assigns its own thread. This is because we are called privately, and
* don't want to expose this method. I don't like hiding the side effects like this, but
* in this case I'm making an exception.
* TODO: Need logic for when to do reloadBookList() vs. getBooks()
*/
private Observable<Map<Installer, List<Book>>> refreshModules() {
if (availableModules == null) {
availableModules = Observable.from(installers)
.map(new Func1<Installer, Map<Installer, List<Book>>>() {
@Override
public Map<Installer, List<Book>> call(Installer installer) {
Map<Installer, List<Book>> map = new HashMap<Installer, List<Book>>();
try {
installer.reloadBookList();
map.put(installer, installer.getBooks());
} catch (InstallException e) {
e.printStackTrace();
}
return map;
}
}).subscribeOn(Schedulers.io())
.cache();
// Set refresh complete when it is.
availableModules.observeOn(Schedulers.io())
.subscribe(new Action1<Map<Installer, List<Book>>>() {
@Override
public void call(Map<Installer, List<Book>> onNext) {}
}, new Action1<Throwable>() {
@Override
public void call(Throwable onError) {}
}, new Action0() {
@Override
public void call() {
refreshComplete.set(true);
}
});
}
return availableModules;
}
public Observable<Book> getAvailableModulesFlattened() {
return availableModules
// First flatten the Map to its lists
.flatMap(new Func1<Map<Installer, List<Book>>, Observable<? extends List<Book>>>() {
@Override
public Observable<? extends List<Book>> call(Map<Installer, List<Book>> books) {
return Observable.from(books.values());
}
})
// Then flatten the lists
.flatMap(new Func1<List<Book>, Observable<? extends Book>>() {
@Override
public Observable<? extends Book> call(List<Book> t1) {
return Observable.from(t1);
}
});
}
/**
* Find the installer that a Book comes from.
* TODO: Should this be @link{Observable} so we don't have to block?
* @param b The book to search for
* @return The Installer that should be used for this book.
*/
public Installer installerFromBook(final Book b) {
Map<Installer, List<Book>> element = availableModules
.filter(new Func1<Map<Installer, List<Book>>, Boolean>() {
@Override
public Boolean call(Map<Installer, List<Book>> installerListMap) {
for (List<Book> element : installerListMap.values()) {
if (element.contains(b)) {
return true;
}
}
return false;
}
})
.toBlocking()
.first();
return element.entrySet().iterator().next().getKey();
}
public boolean isRefreshComplete() {
return refreshComplete.get();
}
}

View File

@ -0,0 +1,46 @@
package org.bspeice.minimalbible.activity.downloader.manager
import org.crosswire.jsword.book.install.Installer
import java.util.concurrent.atomic.AtomicBoolean
import rx.Observable
import org.crosswire.jsword.book.Book
import rx.schedulers.Schedulers
/**
* Created by bspeice on 10/22/14.
*/
class RefreshManager(val installers: Collection<Installer>) {
val refreshComplete = AtomicBoolean()
val availableModules: Observable<Map<Installer, List<Book>>> =
Observable.from(installers)
.map {
if (doReload()) {
it.reloadBookList()
}
mapOf(Pair(it, it.getBooks()))
}
.subscribeOn(Schedulers.io())
.cache();
val availableModulesFlat: Observable<Book>
get() = availableModules
// Map -> Lists
.flatMap { Observable.from(it.values()) }
// Lists -> Single list
.flatMap { Observable.from(it) };
// Constructor - Split from the value creation because `subscribe` returns
// the subscriber object, not the underlying value
{
availableModules.subscribe({}, {}, { refreshComplete set true })
}
fun doReload(): Boolean = true
fun installerFromBook(b: Book): Observable<Installer> = Observable.just(
availableModules.filter {
it.flatMap { it.value } contains b
}
.toBlocking().first().entrySet().first().getKey())
}

View File

@ -22,7 +22,7 @@ class BibleViewClient(val b: Book, val lookup: VerseLookupService,
val v = Verse(b.getVersification(), ordinal) val v = Verse(b.getVersification(), ordinal)
// TODO: WebView should notify us what verse it's on // TODO: WebView should notify us what verse it's on
subject?.onNext(v.getBook().toString() + " " + v.getChapter() + ":" + v.getVerse()) subject?.onNext(v.getBook().toString() + " " + v.getChapter() + ":" + v.getVerse())
return lookup.getJsonVerse(v) as String return lookup.getJsonVerse(v)
} }
JavascriptInterface fun getVerses(first: Int, count: Int): String { JavascriptInterface fun getVerses(first: Int, count: Int): String {

View File

@ -33,7 +33,7 @@ class OsisParser(v: Verse) : DefaultHandler() {
doWrite.pop() doWrite.pop()
} }
override fun characters(ch: CharArray?, start: Int, length: Int) { override fun characters(ch: CharArray?, start: Int, length: Int) {
if (doWrite.peek() as Boolean) if (doWrite.peek())
verseContent.appendContent(String(ch as CharArray)) verseContent.appendContent(String(ch as CharArray))
} }
} }

View File

@ -21,7 +21,7 @@ class VerseContent(v: Verse) {
public fun toJson(): String { public fun toJson(): String {
// Lazy load Gson - not likely that we'll call this method multiple times, so // Lazy load Gson - not likely that we'll call this method multiple times, so
// don't have to worry about a penalty there. // don't have to worry about a penalty there.
return Gson().toJson(this) as String return Gson().toJson(this)
} }
public fun appendContent(content: String) { public fun appendContent(content: String) {

View File

@ -22,11 +22,11 @@ class VersificationUtil() {
} }
fun getBookNames(b: Book): Observable<String> { fun getBookNames(b: Book): Observable<String> {
return Observable.from(b.getVersification().getBookNames()) as Observable return Observable.from(b.getVersification().getBookNames())
} }
fun getBooks(b: Book): Observable<BibleBook> { fun getBooks(b: Book): Observable<BibleBook> {
return Observable.from(b.getVersification().getBooks()) as Observable return Observable.from(b.getVersification().getBooks())
} }
fun getChapterCount(b: Book, bibleBook: BibleBook): Int { fun getChapterCount(b: Book, bibleBook: BibleBook): Int {
@ -34,7 +34,7 @@ class VersificationUtil() {
} }
fun getBookName(b: Book, bibleBook: BibleBook): String { fun getBookName(b: Book, bibleBook: BibleBook): String {
return b.getVersification().getLongName(bibleBook) as String return b.getVersification().getLongName(bibleBook)
} }
fun getVersification(b: Book): Versification { fun getVersification(b: Book): Versification {
@ -58,7 +58,7 @@ fun Versification.getBooks(): List<BibleBook> {
} }
fun Versification.getBookNames(): List<String> { fun Versification.getBookNames(): List<String> {
return this.getBooks().map { this.getLongName(it) as String } return this.getBooks().map { this.getLongName(it) }
} }
fun Versification.getChapterCount(b: BibleBook): Int { fun Versification.getChapterCount(b: BibleBook): Int {
@ -70,7 +70,7 @@ fun Book.getVersification(): Versification {
this.getBookMetaData()!!.getProperty(BookMetaData.KEY_VERSIFICATION).toString() this.getBookMetaData()!!.getProperty(BookMetaData.KEY_VERSIFICATION).toString()
) )
if (v == null) { if (v == null) {
Log.e(getClass()!!.getSimpleName(), "Invalid book: " + this.getInitials()) Log.e(javaClass<Book>().getSimpleName(), "Invalid book: " + this.getInitials())
throw InvalidBookException(this.getInitials()) throw InvalidBookException(this.getInitials())
} else } else
return v return v

View File

@ -1,4 +1,4 @@
#Sat Jul 19 23:18:06 EDT 2014 #Wed Oct 22 20:42:04 EDT 2014
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME