mirror of
https://github.com/MinimalBible/MinimalBible
synced 2024-11-22 07:58:20 -05:00
Merge branch 'master' of http://github.com/MinimalBible/MinimalBible
This commit is contained in:
commit
3ed3d6c08b
@ -5,4 +5,4 @@ script:
|
|||||||
- ./gradlew test
|
- ./gradlew test
|
||||||
|
|
||||||
after_success:
|
after_success:
|
||||||
- ./gradlew jacocoTestReport coveralls --stacktrace
|
- ./gradlew jacocoTestReport coveralls
|
||||||
|
@ -22,6 +22,12 @@ repositories {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test {
|
||||||
|
testLogging {
|
||||||
|
exceptionFormat = 'full'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
def androidModule = project(':app')
|
def androidModule = project(':app')
|
||||||
def firstVariant = androidModule.android.applicationVariants.toList().first()
|
def firstVariant = androidModule.android.applicationVariants.toList().first()
|
||||||
|
|
||||||
@ -30,7 +36,7 @@ dependencies {
|
|||||||
|
|
||||||
testCompile 'junit:junit:4.+'
|
testCompile 'junit:junit:4.+'
|
||||||
testCompile 'org.robolectric:robolectric:+'
|
testCompile 'org.robolectric:robolectric:+'
|
||||||
testCompile 'org.mockito:mockito-all:+'
|
testCompile 'org.mockito:mockito-core:+'
|
||||||
testCompile 'com.jayway.awaitility:awaitility:+'
|
testCompile 'com.jayway.awaitility:awaitility:+'
|
||||||
testCompile 'org.jetbrains.spek:spek:+'
|
testCompile 'org.jetbrains.spek:spek:+'
|
||||||
|
|
||||||
|
@ -0,0 +1,82 @@
|
|||||||
|
package org.bspeice.minimalbible.activity.downloader
|
||||||
|
|
||||||
|
import org.jetbrains.spek.api.Spek
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
import android.content.DialogInterface
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by bspeice on 11/22/14.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class BookListFragmentSpek : Spek() {{
|
||||||
|
|
||||||
|
given("A BookListFragment with showDialog() mocked out") {
|
||||||
|
val fragment = object : BookListFragment() {
|
||||||
|
var condition = false
|
||||||
|
override fun showDialog() {
|
||||||
|
condition = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on("attempting to display modules with the dialog not shown already") {
|
||||||
|
fragment.displayModules(false)
|
||||||
|
|
||||||
|
it("should show the download dialog") {
|
||||||
|
assertTrue(fragment.condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
given("a BookListFragment with displayLanguageSpinner() mocked out") {
|
||||||
|
val fragment = object : BookListFragment() {
|
||||||
|
var condition = false
|
||||||
|
|
||||||
|
override fun displayLanguageSpinner() {
|
||||||
|
condition = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on("attempting to display modules with the dialog already shown") {
|
||||||
|
fragment.displayModules(true)
|
||||||
|
|
||||||
|
it("should show the available languages spinner") {
|
||||||
|
assertTrue(fragment.condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
given("a DownloadDialogListener with with buttonPositive() mocked out") {
|
||||||
|
val listener = object : BookListFragment.DownloadDialogListener(null, null) {
|
||||||
|
var condition = false
|
||||||
|
override fun buttonPositive() {
|
||||||
|
condition = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on("handling a positive button press") {
|
||||||
|
listener.handleButton(DialogInterface.BUTTON_POSITIVE)
|
||||||
|
|
||||||
|
it("should call the proper handler") {
|
||||||
|
assertTrue(listener.condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
given("A DownloadDialogListener with buttonNegative() mocked out") {
|
||||||
|
val listener = object : BookListFragment.DownloadDialogListener(null, null) {
|
||||||
|
var condition = false
|
||||||
|
override fun buttonNegative() {
|
||||||
|
condition = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
on("handling a negative button press") {
|
||||||
|
listener.handleButton(DialogInterface.BUTTON_NEGATIVE)
|
||||||
|
|
||||||
|
it("should call the proper handler") {
|
||||||
|
assertTrue(listener.condition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,70 +0,0 @@
|
|||||||
package org.bspeice.minimalbible.test.activity.downloader;
|
|
||||||
|
|
||||||
import org.bspeice.minimalbible.MBTestCase;
|
|
||||||
import org.bspeice.minimalbible.activity.downloader.BookListFragment;
|
|
||||||
import org.crosswire.common.util.Language;
|
|
||||||
import org.crosswire.jsword.book.Book;
|
|
||||||
import org.crosswire.jsword.book.BookCategory;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
|
|
||||||
import rx.Observable;
|
|
||||||
import rx.functions.Action1;
|
|
||||||
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
public class BookListFragmentTest extends MBTestCase {
|
|
||||||
|
|
||||||
public void testBooksByLanguage() throws Exception {
|
|
||||||
BookCategory bibleCategory = BookCategory.BIBLE;
|
|
||||||
BookCategory dictionaryCategory = BookCategory.DICTIONARY;
|
|
||||||
Language russianLanguage = new Language("ru");
|
|
||||||
Language englishLanguage = new Language("en");
|
|
||||||
|
|
||||||
final Book russianBible = Mockito.mock(Book.class);
|
|
||||||
when(russianBible.getBookCategory()).thenReturn(bibleCategory);
|
|
||||||
when(russianBible.getLanguage()).thenReturn(russianLanguage);
|
|
||||||
|
|
||||||
final Book englishBible = Mockito.mock(Book.class);
|
|
||||||
when(englishBible.getBookCategory()).thenReturn(bibleCategory);
|
|
||||||
when(englishBible.getLanguage()).thenReturn(englishLanguage);
|
|
||||||
|
|
||||||
final Book englishDictionary = Mockito.mock(Book.class);
|
|
||||||
when(englishDictionary.getBookCategory()).thenReturn(dictionaryCategory);
|
|
||||||
when(englishDictionary.getLanguage()).thenReturn(englishLanguage);
|
|
||||||
|
|
||||||
Observable<Book> mockBooks = Observable.just(russianBible, englishBible,
|
|
||||||
englishDictionary);
|
|
||||||
|
|
||||||
// Since we're not testing lifecycle here, don't worry about newInstance()
|
|
||||||
TestableBookListFragment fragment = new TestableBookListFragment();
|
|
||||||
|
|
||||||
fragment.booksByLanguage(mockBooks, englishLanguage, bibleCategory)
|
|
||||||
.subscribe(new Action1<Book>() {
|
|
||||||
@Override
|
|
||||||
public void call(Book book) {
|
|
||||||
assertEquals(englishBible, book);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fragment.booksByLanguage(mockBooks, russianLanguage, bibleCategory)
|
|
||||||
.subscribe(new Action1<Book>() {
|
|
||||||
@Override
|
|
||||||
public void call(Book book) {
|
|
||||||
assertEquals(russianBible, book);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
fragment.booksByLanguage(mockBooks, englishLanguage, dictionaryCategory)
|
|
||||||
.subscribe(new Action1<Book>() {
|
|
||||||
@Override
|
|
||||||
public void call(Book book) {
|
|
||||||
assertEquals(englishDictionary, book);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TestableBookListFragment extends BookListFragment {
|
|
||||||
@Override
|
|
||||||
public Observable<Book> booksByLanguage(Observable<Book> books, Language language, BookCategory category) {
|
|
||||||
return super.booksByLanguage(books, language, category);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,7 +2,6 @@ package org.bspeice.minimalbible.activity.downloader;
|
|||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.AlertDialog;
|
import android.app.AlertDialog;
|
||||||
import android.app.ProgressDialog;
|
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -11,7 +10,6 @@ import android.view.ViewGroup;
|
|||||||
import android.widget.ArrayAdapter;
|
import android.widget.ArrayAdapter;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
import android.widget.Spinner;
|
import android.widget.Spinner;
|
||||||
import android.widget.SpinnerAdapter;
|
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import org.bspeice.minimalbible.Injector;
|
import org.bspeice.minimalbible.Injector;
|
||||||
@ -45,9 +43,9 @@ public class BookListFragment extends BaseFragment {
|
|||||||
protected static final String ARG_BOOK_CATEGORY = "book_category";
|
protected static final String ARG_BOOK_CATEGORY = "book_category";
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected DownloadPrefs downloadPrefs;
|
DownloadPrefs downloadPrefs;
|
||||||
protected ProgressDialog refreshDialog;
|
@Inject
|
||||||
@Inject RefreshManager refreshManager;
|
RefreshManager refreshManager;
|
||||||
@Inject
|
@Inject
|
||||||
List<Language> availableLanguages;
|
List<Language> availableLanguages;
|
||||||
|
|
||||||
@ -56,7 +54,7 @@ public class BookListFragment extends BaseFragment {
|
|||||||
@InjectView(R.id.spn_available_languages)
|
@InjectView(R.id.spn_available_languages)
|
||||||
Spinner languagesSpinner;
|
Spinner languagesSpinner;
|
||||||
|
|
||||||
private LayoutInflater inflater;
|
LayoutInflater inflater;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a new instance of this fragment for the given section number.
|
* Returns a new instance of this fragment for the given section number.
|
||||||
@ -95,61 +93,44 @@ public class BookListFragment extends BaseFragment {
|
|||||||
.getString(ARG_BOOK_CATEGORY));
|
.getString(ARG_BOOK_CATEGORY));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void displayModules() {
|
||||||
|
displayModules(downloadPrefs.hasShownDownloadDialog());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trigger the functionality to display a list of modules. Prompts user if downloading
|
* Trigger the functionality to display a list of modules. Prompts user if downloading
|
||||||
* from the internet is allowable.
|
* from the internet is allowable.
|
||||||
*/
|
*/
|
||||||
protected void displayModules() {
|
void displayModules(boolean dialogDisplayed) {
|
||||||
boolean dialogDisplayed = downloadPrefs.hasShownDownloadDialog();
|
if (!dialogDisplayed) {
|
||||||
|
showDialog();
|
||||||
if (!dialogDisplayed) {
|
} else {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
displayLanguageSpinner();
|
||||||
DownloadDialogListener dialogListener = new DownloadDialogListener();
|
}
|
||||||
builder.setMessage(
|
|
||||||
"About to contact servers to download content. Continue?")
|
|
||||||
.setPositiveButton("Yes", dialogListener)
|
|
||||||
.setNegativeButton("No", dialogListener)
|
|
||||||
.setCancelable(false).show();
|
|
||||||
} else {
|
|
||||||
refreshModules();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void showDialog() {
|
||||||
* Do the work of refreshing modules (download manager handles using cached copy vs. actual
|
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
* refresh), and then displaying them when ready.
|
DownloadDialogListener dialogListener = new DownloadDialogListener(this, downloadPrefs);
|
||||||
*/
|
builder.setMessage(
|
||||||
private void refreshModules() {
|
"About to contact servers to download content. Continue?")
|
||||||
// Check if the downloadManager has already refreshed everything
|
.setPositiveButton("Yes", dialogListener)
|
||||||
if (!refreshManager.getRefreshComplete().get()) {
|
.setNegativeButton("No", dialogListener)
|
||||||
// downloadManager is in progress of refreshing
|
.setCancelable(false).show();
|
||||||
refreshDialog = new ProgressDialog(getActivity());
|
|
||||||
refreshDialog.setMessage("Refreshing available modules...");
|
|
||||||
refreshDialog.setCancelable(false);
|
|
||||||
refreshDialog.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
languagesSpinner.setAdapter(getLocaleSpinner());
|
|
||||||
if (BookListFragment.this.getActivity() != null) {
|
|
||||||
// On a screen rotate, getActivity() will be null. But, the activity
|
|
||||||
// will already have been set up correctly, so we don't need to worry
|
|
||||||
// about it.
|
|
||||||
// If not null, we need to set it up now.
|
|
||||||
setInsetsSpinner(BookListFragment.this.getActivity(), languagesSpinner);
|
|
||||||
}
|
|
||||||
if (refreshDialog != null) {
|
|
||||||
refreshDialog.cancel();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
void displayLanguageSpinner() {
|
||||||
// getAvailableLanguagesList() will not return null
|
|
||||||
SpinnerAdapter getLocaleSpinner() {
|
|
||||||
ArrayAdapter<Object> adapter = new ArrayAdapter<Object>(this.getActivity(),
|
ArrayAdapter<Object> adapter = new ArrayAdapter<Object>(this.getActivity(),
|
||||||
android.R.layout.simple_spinner_item,
|
android.R.layout.simple_spinner_item,
|
||||||
availableLanguages.toArray());
|
availableLanguages.toArray());
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
return adapter;
|
languagesSpinner.setAdapter(adapter);
|
||||||
|
|
||||||
|
if (BookListFragment.this.getActivity() != null) {
|
||||||
|
// On a screen rotate, getActivity() will be null, but the activity
|
||||||
|
// will already have been set up. If not null, we need to set it up now.
|
||||||
|
setInsetsSpinner(BookListFragment.this.getActivity(), languagesSpinner);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
@ -195,35 +176,53 @@ public class BookListFragment extends BaseFragment {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private class DownloadDialogListener implements
|
static class DownloadDialogListener implements
|
||||||
DialogInterface.OnClickListener {
|
DialogInterface.OnClickListener {
|
||||||
|
BookListFragment fragment;
|
||||||
|
DownloadPrefs downloadPrefs;
|
||||||
|
|
||||||
|
DownloadDialogListener(BookListFragment fragment, DownloadPrefs downloadPrefs) {
|
||||||
|
this.fragment = fragment;
|
||||||
|
this.downloadPrefs = downloadPrefs;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onClick(@NotNull DialogInterface dialog, int which) {
|
public void onClick(@NotNull DialogInterface dialog, int which) {
|
||||||
downloadPrefs.hasShownDownloadDialog(true);
|
downloadPrefs.hasShownDownloadDialog(true);
|
||||||
|
handleButton(which);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handleButton(int which) {
|
||||||
switch (which) {
|
switch (which) {
|
||||||
case DialogInterface.BUTTON_POSITIVE:
|
case DialogInterface.BUTTON_POSITIVE:
|
||||||
// Clicked ready to continue - allow downloading in the future
|
buttonPositive();
|
||||||
downloadPrefs.hasEnabledDownload(true);
|
|
||||||
|
|
||||||
// And warn them that it has been enabled in the future.
|
|
||||||
Toast.makeText(getActivity(),
|
|
||||||
"Downloading now enabled. Disable in settings.",
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
refreshModules();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// case DialogInterface.BUTTON_NEGATIVE:
|
// case DialogInterface.BUTTON_NEGATIVE:
|
||||||
default:
|
default:
|
||||||
// Clicked to not download - Permanently disable downloading
|
buttonNegative();
|
||||||
downloadPrefs.hasEnabledDownload(false);
|
|
||||||
Toast.makeText(getActivity(),
|
|
||||||
"Disabling downloading. Re-enable it in settings.",
|
|
||||||
Toast.LENGTH_SHORT).show();
|
|
||||||
refreshModules();
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
void buttonPositive() {
|
||||||
|
// Clicked ready to continue - allow downloading in the future
|
||||||
|
downloadPrefs.hasEnabledDownload(true);
|
||||||
|
|
||||||
|
// And warn them that it has been enabled in the future.
|
||||||
|
showToast("Downloading now enabled. Disable in settings");
|
||||||
|
fragment.displayModules();
|
||||||
|
}
|
||||||
|
|
||||||
|
void buttonNegative() {
|
||||||
|
// Clicked to not download - Permanently disable downloading
|
||||||
|
downloadPrefs.hasEnabledDownload(false);
|
||||||
|
showToast("Disabling downloading. Re-enable it in settings.");
|
||||||
|
fragment.getActivity().finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
void showToast(String text) {
|
||||||
|
Toast.makeText(fragment.getActivity(), text, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -48,9 +48,9 @@ class RefreshManager(val installers: Collection<Installer>,
|
|||||||
|
|
||||||
val fifteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1296000
|
val fifteenDaysAgo = Calendar.getInstance().getTime().getTime() - 1296000
|
||||||
|
|
||||||
fun doReload(enabledDownload: Boolean, lastUpdated: Long,
|
fun doReload(downloadEnabled: Boolean, lastUpdated: Long,
|
||||||
networkState: Int? = ConnectivityManager.TYPE_DUMMY): Boolean =
|
networkState: Int? = ConnectivityManager.TYPE_DUMMY): Boolean =
|
||||||
if (!enabledDownload || networkState != ConnectivityManager.TYPE_WIFI)
|
if (!downloadEnabled || networkState != ConnectivityManager.TYPE_WIFI)
|
||||||
false
|
false
|
||||||
else if (lastUpdated < fifteenDaysAgo)
|
else if (lastUpdated < fifteenDaysAgo)
|
||||||
true
|
true
|
||||||
|
@ -4,7 +4,7 @@ buildscript {
|
|||||||
ext.kotlin_version = '0.9.206'
|
ext.kotlin_version = '0.9.206'
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:0.13.+'
|
classpath 'com.android.tools.build:gradle:0.13.+'
|
||||||
@ -16,6 +16,6 @@ buildscript {
|
|||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
jcenter()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user