mirror of
https://github.com/MinimalBible/MinimalBible
synced 2024-11-22 07:58:20 -05:00
RefreshManager going functional!
This commit is contained in:
parent
6d15167100
commit
22fd32b26d
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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())
|
||||||
|
}
|
@ -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 {
|
||||||
|
@ -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))
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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) {
|
||||||
|
@ -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
|
||||||
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@ -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
|
||||||
|
Loading…
Reference in New Issue
Block a user