diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 57cab64..598523f 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,6 +11,10 @@ + + + diff --git a/app/src/main/assets/book.html b/app/src/main/assets/book.html new file mode 100644 index 0000000..75f4951 --- /dev/null +++ b/app/src/main/assets/book.html @@ -0,0 +1,11 @@ + + +
+ + + + \ No newline at end of file diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivityModules.java b/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivityModules.java index 8a4b339..73a8e6d 100644 --- a/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivityModules.java +++ b/app/src/main/java/org/bspeice/minimalbible/activity/downloader/DownloadActivityModules.java @@ -1,5 +1,6 @@ package org.bspeice.minimalbible.activity.downloader; +import org.bspeice.minimalbible.Injector; import org.bspeice.minimalbible.MinimalBibleModules; import org.bspeice.minimalbible.activity.downloader.manager.BookDownloadManager; import org.bspeice.minimalbible.activity.downloader.manager.BookDownloadThread; @@ -49,6 +50,11 @@ public class DownloadActivityModules { return activity; } + @Provides @Singleton + Injector provideActivityInjector() { + return activity; + } + @Provides @Singleton BookDownloadManager provideBookDownloadManager() { return new BookDownloadManager(activity); diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java new file mode 100644 index 0000000..d87e4f1 --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewer.java @@ -0,0 +1,159 @@ +package org.bspeice.minimalbible.activity.viewer; + +import android.content.Intent; +import android.os.Bundle; +import android.os.Looper; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.widget.DrawerLayout; +import android.support.v7.app.ActionBar; +import android.util.Log; +import android.view.Menu; +import android.view.MenuItem; + +import org.bspeice.minimalbible.Injector; +import org.bspeice.minimalbible.MinimalBible; +import org.bspeice.minimalbible.R; +import org.bspeice.minimalbible.activity.BaseActivity; +import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; +import org.bspeice.minimalbible.activity.downloader.DownloadActivity; +import org.bspeice.minimalbible.activity.downloader.DownloadActivityModules; +import org.crosswire.jsword.book.Book; + +import javax.inject.Inject; + +import dagger.ObjectGraph; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; + +public class BibleViewer extends BaseActivity implements + BaseNavigationDrawerFragment.NavigationDrawerCallbacks, + Injector { + + @Inject BookManager bookManager; + + private ObjectGraph bvObjectGraph; + /** + * Build a scoped object graph for anything used by the DownloadActivity + */ + private void buildObjGraph() { + if (bvObjectGraph == null) { + bvObjectGraph = MinimalBible.get(this) + .plus(new BibleViewerModules()); + } + bvObjectGraph.inject(this); + } + + @Override + public void inject(Object o) { + buildObjGraph(); + bvObjectGraph.inject(o); + } + + /** + * Fragment managing the behaviors, interactions and presentation of the + * navigation drawer. + */ + private ViewerNavDrawerFragment mNavigationDrawerFragment; + + /** + * Used to store the last screen title. For use in + * {@link #restoreActionBar()}. + */ + private CharSequence mTitle; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + this.inject(this); + + // If no books are installed, we need to download one first. + int count = bookManager.getInstalledBooks() + .count() + .toBlocking() + .last(); + if (count <= 0) { + Intent i = new Intent(this, DownloadActivity.class); + startActivityForResult(i, 0); + finish(); + } else { + bookManager.getInstalledBooks() + .first() + .subscribeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(Book book) { + Log.d("BibleViewer", "Subscribed to display book: " + book.getName()); + displayMainBook(book); + } + }); + } + + setContentView(R.layout.activity_bible_viewer); + + mNavigationDrawerFragment = (ViewerNavDrawerFragment) getSupportFragmentManager() + .findFragmentById(R.id.navigation_drawer); + mTitle = getTitle(); + + // Set up the drawer. + mNavigationDrawerFragment.setUp(R.id.navigation_drawer, + (DrawerLayout) findViewById(R.id.drawer_layout)); + } + + @Override + public void onNavigationDrawerItemSelected(int position) { + // Handle a navigation movement + } + + public void setActionBarTitle(String title) { + ActionBar actionBar = getSupportActionBar(); + mTitle = title; + actionBar.setTitle(title); + } + + public void restoreActionBar() { + ActionBar actionBar = getSupportActionBar(); + actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD); + actionBar.setDisplayShowTitleEnabled(true); + actionBar.setTitle(mTitle); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + if (!mNavigationDrawerFragment.isDrawerOpen()) { + // Only show items in the action bar relevant to this screen + // if the drawer is not showing. Otherwise, let the drawer + // decide what to show in the action bar. + getMenuInflater().inflate(R.menu.main, menu); + restoreActionBar(); + return true; + } + return super.onCreateOptionsMenu(menu); + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + if (id == R.id.action_settings) { + return true; + } else if (id == R.id.action_downloads) { + startActivity(new Intent(this, DownloadActivity.class)); + } + return super.onOptionsItemSelected(item); + } + + private void displayMainBook(Book b) { + Log.d("BibleViewer", "Initializing main book: " + b.getName()); + Log.d("MainThread?", Boolean.toString(Looper.myLooper() == Looper.getMainLooper())); + FragmentManager fragmentManager = getSupportFragmentManager(); + Fragment f = BookFragment.newInstance(b.getName(), this); + fragmentManager.beginTransaction() + .replace(R.id.container, f) + .commit(); + } + +} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java new file mode 100644 index 0000000..a53d410 --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BibleViewerModules.java @@ -0,0 +1,15 @@ +package org.bspeice.minimalbible.activity.viewer; + +import dagger.Module; + +/** + * Created by bspeice on 6/18/14. + */ +@Module( + injects = { + BibleViewer.class, + BookFragment.class + } +) +public class BibleViewerModules { +} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BookFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BookFragment.java new file mode 100644 index 0000000..d0fa594 --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BookFragment.java @@ -0,0 +1,142 @@ +package org.bspeice.minimalbible.activity.viewer; + +import android.app.Activity; +import android.os.Bundle; +import android.util.Log; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebView; +import android.webkit.WebViewClient; + +import org.bspeice.minimalbible.Injector; +import org.bspeice.minimalbible.MinimalBible; +import org.bspeice.minimalbible.R; +import org.bspeice.minimalbible.activity.BaseFragment; +import org.crosswire.jsword.book.Book; + +import java.util.List; + +import javax.inject.Inject; + +import butterknife.ButterKnife; +import butterknife.InjectView; +import rx.android.schedulers.AndroidSchedulers; +import rx.functions.Action1; +import rx.functions.Func1; + +/** + * A placeholder fragment containing a simple view. + */ +public class BookFragment extends BaseFragment { + + @Inject BookManager bookManager; + + @InjectView(R.id.book_content) + WebView mainContent; + + private static final String ARG_BOOK_NAME = "book_name"; + + private Book mBook; + + /** + * Returns a new instance of this fragment for the given section number. + */ + public static BookFragment newInstance(String bookName, Injector injector) { + BookFragment fragment = new BookFragment(); + injector.inject(fragment); + Bundle args = new Bundle(); + args.putString(ARG_BOOK_NAME, bookName); + fragment.setArguments(args); + return fragment; + } + + public BookFragment() { + } + + @Override + public void onCreate(Bundle state) { + super.onCreate(state); + ((Injector)getActivity()).inject(this); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_viewer_main, container, + false); + ButterKnife.inject(this, rootView); + mainContent.getSettings().setJavaScriptEnabled(true); + + // TODO: Load initial text from SharedPreferences + + // And due to Observable async, we can kick off fetching the actual book asynchronously! + bookManager.getInstalledBooks() + .first(new Func1() { + @Override + public Boolean call(Book book) { + String mBookName = getArguments().getString(ARG_BOOK_NAME); + return book.getName().equals(mBookName); + } + }) + .observeOn(AndroidSchedulers.mainThread()) + .subscribe(new Action1() { + @Override + public void call(Book book) { + BookFragment.this.mBook = book; + displayBook(book); + } + }, new Action1() { + @Override + public void call(Throwable throwable) { + Log.d("BookFragment", "No books installed?"); + } + }); + + return rootView; + } + + // TODO: Remove? + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + } + + private void displayBook(Book b) { + Log.d("BookFragment", b.getName()); + ((BibleViewer)getActivity()).setActionBarTitle(b.getInitials()); + mainContent.loadUrl(getString(R.string.content_page)); + mainContent.setWebViewClient(new WebViewClient(){ + @Override + public void onPageFinished(WebView view, String url) { + super.onPageFinished(view, url); + invokeJavascript("set_content", BookFragment.this.mBook.getName()); + } + }); + + } + + private void invokeJavascript(String function, Object arg) { + mainContent.loadUrl("javascript:" + function + "('" + arg.toString() + "')"); + } + + private void invokeJavascript(String function, List args) { + mainContent.loadUrl("javascript:" + function + "(" + joinString(",", args.toArray()) + ")"); + } + + // Convenience from http://stackoverflow.com/a/17795110/1454178 + public static String joinString(String join, Object... strings) { + if (strings == null || strings.length == 0) { + return ""; + } else if (strings.length == 1) { + return strings[0].toString(); + } else { + StringBuilder sb = new StringBuilder(); + sb.append(strings[0]); + for (int i = 1; i < strings.length; i++) { + sb.append(join).append(strings[i].toString()); + } + return sb.toString(); + } + } +} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BookManager.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BookManager.java new file mode 100644 index 0000000..8bf2108 --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/BookManager.java @@ -0,0 +1,50 @@ +package org.bspeice.minimalbible.activity.viewer; + +import org.crosswire.jsword.book.Book; +import org.crosswire.jsword.book.Books; + +import javax.inject.Inject; +import javax.inject.Singleton; + +import rx.Observable; +import rx.functions.Action0; +import rx.functions.Action1; +import rx.schedulers.Schedulers; + +/** + * Created by bspeice on 6/18/14. + */ +@Singleton +public class BookManager { + + private Observable installedBooks; + private Boolean refreshComplete; + + @Inject + BookManager() { + installedBooks = Observable.from(Books.installed().getBooks()) + .cache(); + installedBooks.subscribeOn(Schedulers.io()) + .subscribe(new Action1() { + @Override + public void call(Book book) {} + }, new Action1() { + @Override + public void call(Throwable throwable) {} + }, new Action0() { + @Override + public void call() { + BookManager.this.refreshComplete = true; + } + }); + } + + public Observable getInstalledBooks() { + return installedBooks; + } + + public Boolean isRefreshComplete() { + return refreshComplete; + } + +} diff --git a/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java new file mode 100644 index 0000000..47d3c32 --- /dev/null +++ b/app/src/main/java/org/bspeice/minimalbible/activity/viewer/ViewerNavDrawerFragment.java @@ -0,0 +1,38 @@ +package org.bspeice.minimalbible.activity.viewer; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListView; + +import org.bspeice.minimalbible.R; +import org.bspeice.minimalbible.activity.BaseNavigationDrawerFragment; + +public class ViewerNavDrawerFragment extends BaseNavigationDrawerFragment { + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + mDrawerListView = (ListView) inflater.inflate( + R.layout.fragment_navigation_drawer, container, false); + mDrawerListView + .setOnItemClickListener(new AdapterView.OnItemClickListener() { + @Override + public void onItemClick(AdapterView parent, View view, + int position, long id) { + selectItem(position); + } + }); + mDrawerListView.setAdapter(new ArrayAdapter(getActionBar() + .getThemedContext(), android.R.layout.simple_list_item_1, + android.R.id.text1, new String[] { + getString(R.string.title_section1), + getString(R.string.title_section2), + getString(R.string.title_section3)})); + mDrawerListView.setItemChecked(mCurrentSelectedPosition, true); + return mDrawerListView; + } +} diff --git a/app/src/main/res/layout/activity_bible_viewer.xml b/app/src/main/res/layout/activity_bible_viewer.xml new file mode 100644 index 0000000..043d893 --- /dev/null +++ b/app/src/main/res/layout/activity_bible_viewer.xml @@ -0,0 +1,42 @@ + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/fragment_viewer_main.xml b/app/src/main/res/layout/fragment_viewer_main.xml new file mode 100644 index 0000000..9147032 --- /dev/null +++ b/app/src/main/res/layout/fragment_viewer_main.xml @@ -0,0 +1,12 @@ + + + + + diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml new file mode 100644 index 0000000..8eafe31 --- /dev/null +++ b/app/src/main/res/menu/main.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/app/src/main/res/values/html_strings.xml b/app/src/main/res/values/html_strings.xml new file mode 100644 index 0000000..a228ccf --- /dev/null +++ b/app/src/main/res/values/html_strings.xml @@ -0,0 +1,4 @@ + + + file:///android_asset/book.html + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 12187c7..480439a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,5 +9,6 @@ Close navigation drawer Example action Settings + Downloads