aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/.gitignore1
-rw-r--r--app/app.iml94
-rw-r--r--app/build.gradle26
-rw-r--r--app/libs/volley.jarbin0 -> 85763 bytes
-rw-r--r--app/proguard-rules.pro17
-rw-r--r--app/src/androidTest/java/com/camilstaps/taize/ApplicationTest.java13
-rw-r--r--app/src/main/AndroidManifest.xml32
-rw-r--r--app/src/main/java/com/camilstaps/common/Listener.java20
-rw-r--r--app/src/main/java/com/camilstaps/common/NullListener.java14
-rw-r--r--app/src/main/java/com/camilstaps/rss/RetrieveFeedTask.java37
-rw-r--r--app/src/main/java/com/camilstaps/rss/RssParser.java293
-rw-r--r--app/src/main/java/com/camilstaps/taize/Bible.java86
-rw-r--r--app/src/main/java/com/camilstaps/taize/BibleText.java73
-rw-r--r--app/src/main/java/com/camilstaps/taize/MainActivity.java165
-rw-r--r--app/src/main/java/com/camilstaps/taize/NavigationDrawerFragment.java317
-rw-r--r--app/src/main/java/com/camilstaps/taize/SettingsActivity.java66
-rw-r--r--app/src/main/java/com/camilstaps/taize/Taize.java224
-rw-r--r--app/src/main/res/drawable-hdpi/drawer_shadow.9.pngbin0 -> 161 bytes
-rw-r--r--app/src/main/res/drawable-hdpi/ic_drawer.pngbin0 -> 2829 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/drawer_shadow.9.pngbin0 -> 142 bytes
-rw-r--r--app/src/main/res/drawable-mdpi/ic_drawer.pngbin0 -> 2820 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/drawer_shadow.9.pngbin0 -> 174 bytes
-rw-r--r--app/src/main/res/drawable-xhdpi/ic_drawer.pngbin0 -> 2836 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/drawer_shadow.9.pngbin0 -> 208 bytes
-rw-r--r--app/src/main/res/drawable-xxhdpi/ic_drawer.pngbin0 -> 202 bytes
-rw-r--r--app/src/main/res/layout/activity_main.xml40
-rw-r--r--app/src/main/res/layout/fragment_main.xml12
-rw-r--r--app/src/main/res/layout/fragment_navigation_drawer.xml5
-rw-r--r--app/src/main/res/menu/global.xml5
-rw-r--r--app/src/main/res/menu/main.xml8
-rw-r--r--app/src/main/res/mipmap-hdpi/ic_launcher.pngbin0 -> 3418 bytes
-rw-r--r--app/src/main/res/mipmap-mdpi/ic_launcher.pngbin0 -> 2206 bytes
-rw-r--r--app/src/main/res/mipmap-xhdpi/ic_launcher.pngbin0 -> 4842 bytes
-rw-r--r--app/src/main/res/mipmap-xxhdpi/ic_launcher.pngbin0 -> 7718 bytes
-rw-r--r--app/src/main/res/values-w820dp/dimens.xml6
-rw-r--r--app/src/main/res/values/dimens.xml9
-rw-r--r--app/src/main/res/values/preference_values.xml152
-rw-r--r--app/src/main/res/values/strings.xml13
-rw-r--r--app/src/main/res/values/styles.xml8
-rw-r--r--app/src/main/res/xml/preferences.xml27
40 files changed, 1763 insertions, 0 deletions
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 0000000..796b96d
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/app.iml b/app/app.iml
new file mode 100644
index 0000000..2192b64
--- /dev/null
+++ b/app/app.iml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Taizé" external.system.module.version="unspecified" type="JAVA_MODULE" version="4">
+ <component name="FacetManager">
+ <facet type="android-gradle" name="Android-Gradle">
+ <configuration>
+ <option name="GRADLE_PROJECT_PATH" value=":app" />
+ </configuration>
+ </facet>
+ <facet type="android" name="Android">
+ <configuration>
+ <option name="SELECTED_BUILD_VARIANT" value="debug" />
+ <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" />
+ <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" />
+ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" />
+ <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" />
+ <option name="SOURCE_GEN_TASK_NAME" value="generateDebugSources" />
+ <option name="TEST_SOURCE_GEN_TASK_NAME" value="generateDebugAndroidTestSources" />
+ <option name="ALLOW_USER_CONFIGURATION" value="false" />
+ <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" />
+ <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" />
+ <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" />
+ <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" />
+ </configuration>
+ </facet>
+ </component>
+ <component name="NewModuleRootManager" inherit-compiler-output="false">
+ <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" />
+ <output-test url="file://$MODULE_DIR$/build/intermediates/classes/androidTest/debug" />
+ <exclude-output />
+ <content url="file://$MODULE_DIR$">
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/debug" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/generated/androidTest/debug" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" />
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/coverage-instrumented-classes" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex-cache" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/jacoco" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/javaResources" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/libs" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/ndk" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" />
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" />
+ <excludeFolder url="file://$MODULE_DIR$/build/outputs" />
+ <excludeFolder url="file://$MODULE_DIR$/build/tmp" />
+ </content>
+ <orderEntry type="jdk" jdkName="Android API 21 Platform" jdkType="Android SDK" />
+ <orderEntry type="sourceFolder" forTests="false" />
+ <orderEntry type="library" exported="" name="support-v4-22.0.0" level="project" />
+ <orderEntry type="library" exported="" name="support-annotations-22.0.0" level="project" />
+ <orderEntry type="library" exported="" name="appcompat-v7-22.0.0" level="project" />
+ <orderEntry type="library" exported="" name="volley" level="project" />
+ </component>
+</module>
+
diff --git a/app/build.gradle b/app/build.gradle
new file mode 100644
index 0000000..bd597c4
--- /dev/null
+++ b/app/build.gradle
@@ -0,0 +1,26 @@
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 21
+ buildToolsVersion "21.1.2"
+
+ defaultConfig {
+ applicationId "com.camilstaps.taize"
+ minSdkVersion 11
+ targetSdkVersion 21
+ versionCode 1
+ versionName "1.0"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+}
+
+dependencies {
+ compile fileTree(dir: 'libs', include: ['*.jar'])
+ compile 'com.android.support:appcompat-v7:22.0.0'
+ compile files('libs/volley.jar')
+}
diff --git a/app/libs/volley.jar b/app/libs/volley.jar
new file mode 100644
index 0000000..d9279b4
--- /dev/null
+++ b/app/libs/volley.jar
Binary files differ
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
new file mode 100644
index 0000000..966ccb1
--- /dev/null
+++ b/app/proguard-rules.pro
@@ -0,0 +1,17 @@
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in /home/camilstaps/Android/Sdk/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the proguardFiles
+# directive in build.gradle.
+#
+# For more details, see
+# http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+# public *;
+#}
diff --git a/app/src/androidTest/java/com/camilstaps/taize/ApplicationTest.java b/app/src/androidTest/java/com/camilstaps/taize/ApplicationTest.java
new file mode 100644
index 0000000..215c930
--- /dev/null
+++ b/app/src/androidTest/java/com/camilstaps/taize/ApplicationTest.java
@@ -0,0 +1,13 @@
+package com.camilstaps.taize;
+
+import android.app.Application;
+import android.test.ApplicationTestCase;
+
+/**
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
+ */
+public class ApplicationTest extends ApplicationTestCase<Application> {
+ public ApplicationTest() {
+ super(Application.class);
+ }
+} \ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..6ae08cb
--- /dev/null
+++ b/app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.camilstaps.taize" >
+
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+
+ <application
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:theme="@style/AppTheme" >
+ <activity
+ android:name=".MainActivity"
+ android:label="@string/app_name" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity
+ android:name=".SettingsActivity"
+ android:label="@string/title_activity_settings"
+ android:parentActivityName=".MainActivity" >
+ <meta-data
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value=".MainActivity" />
+ </activity>
+ </application>
+
+</manifest>
diff --git a/app/src/main/java/com/camilstaps/common/Listener.java b/app/src/main/java/com/camilstaps/common/Listener.java
new file mode 100644
index 0000000..36319c6
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/common/Listener.java
@@ -0,0 +1,20 @@
+package com.camilstaps.common;
+
+/**
+ * Abstract class for something listening for some object
+ * @author Camil Staps
+ */
+public abstract class Listener<T> {
+
+ /**
+ * To be called when the data is successfully retrieved
+ * @param data
+ */
+ public abstract void success(T data);
+
+ /**
+ * To be called when the data could not be retrieved
+ */
+ public abstract void failure();
+
+}
diff --git a/app/src/main/java/com/camilstaps/common/NullListener.java b/app/src/main/java/com/camilstaps/common/NullListener.java
new file mode 100644
index 0000000..c22e76d
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/common/NullListener.java
@@ -0,0 +1,14 @@
+package com.camilstaps.common;
+
+/**
+ * Listener that discards all data and errors.
+ * @author Camil Staps
+ */
+public class NullListener<T> extends Listener<T> {
+
+ @Override
+ public void success(T data) { }
+
+ @Override
+ public void failure() { }
+}
diff --git a/app/src/main/java/com/camilstaps/rss/RetrieveFeedTask.java b/app/src/main/java/com/camilstaps/rss/RetrieveFeedTask.java
new file mode 100644
index 0000000..543c9d6
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/rss/RetrieveFeedTask.java
@@ -0,0 +1,37 @@
+package com.camilstaps.rss;
+
+import android.os.AsyncTask;
+
+import com.camilstaps.common.Listener;
+
+/**
+ * Asynchronously retrieve an RSS feed
+ * @author Camil Staps
+ */
+public class RetrieveFeedTask extends AsyncTask<String, Void, RssParser> {
+
+ Listener<RssParser> listener;
+
+ public void setRssDownloadListener(Listener<RssParser> listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ protected RssParser doInBackground(String... params) {
+ try {
+ RssParser parser = new RssParser(params[0]);
+ return parser;
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ @Override
+ protected void onPostExecute(RssParser results) {
+ if (results != null) {
+ listener.success(results);
+ } else {
+ listener.failure();
+ }
+ }
+}
diff --git a/app/src/main/java/com/camilstaps/rss/RssParser.java b/app/src/main/java/com/camilstaps/rss/RssParser.java
new file mode 100644
index 0000000..2c32abd
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/rss/RssParser.java
@@ -0,0 +1,293 @@
+package com.camilstaps.rss;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import android.util.Log;
+
+/**
+ * RSS parser
+ *
+ * See: http://stackoverflow.com/a/24985128/1544337
+ *
+ * Usage:
+ * RssParser parser = new RssParser(feedUrl);
+ * Log.i("LOG", "Description: " + parser.getItem(3).description); //4th item's description
+ *
+ * @author Camil Staps
+ */
+public class RssParser extends DefaultHandler {
+
+ private StringBuilder content;
+ private boolean inChannel;
+ private boolean inImage;
+ private boolean inItem;
+
+ private ArrayList<Item> items = new ArrayList<Item>();
+ private Channel channel = new Channel();
+
+ private Item lastItem;
+
+
+ public RssParser(String url) {
+ try {
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ SAXParser sp = spf.newSAXParser();
+ XMLReader xr = sp.getXMLReader();
+ URL sourceUrl = new URL(url);
+ xr.setContentHandler(this);
+ xr.parse(new InputSource(sourceUrl.openStream()));
+ }
+ catch (ParserConfigurationException e) {
+ e.printStackTrace();
+ }
+ catch (SAXException e) {
+ e.printStackTrace();
+ }
+ catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+
+ public class Item {
+
+ public String title;
+ public String description;
+ public String link;
+ public String category;
+ public String pubDate;
+ public String guid;
+ }
+
+
+ public class Channel {
+
+ public String title;
+ public String description;
+ public String link;
+ public String lastBuildDate;
+ public String generator;
+ public String imageUrl;
+ public String imageTitle;
+ public String imageLink;
+ public String imageWidth;
+ public String imageHeight;
+ public String imageDescription;
+ public String language;
+ public String copyright;
+ public String pubDate;
+ public String category;
+ public String ttl;
+ }
+
+
+ @Override
+ public void startDocument() throws SAXException {
+ Log.i("LOG", "StartDocument");
+ }
+
+
+ @Override
+ public void endDocument() throws SAXException {
+ Log.i("LOG", "EndDocument");
+ }
+
+
+ @Override
+ public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
+ if (localName.equalsIgnoreCase("image")) {
+ inImage = true;
+ }
+
+ if (localName.equalsIgnoreCase("channel")) {
+ inChannel = true;
+ }
+
+ if (localName.equalsIgnoreCase("item")) {
+ lastItem = new Item();
+ items.add(lastItem);
+ inItem = true;
+ }
+
+ content = new StringBuilder();
+ }
+
+
+ @Override
+ public void endElement(String uri, String localName, String qName) throws SAXException {
+ if (localName.equalsIgnoreCase("image")) {
+ inImage = false;
+ }
+
+ if (localName.equalsIgnoreCase("channel")) {
+ inChannel = false;
+ }
+
+ if (localName.equalsIgnoreCase("item")) {
+ inItem = false;
+ }
+
+ if (localName.equalsIgnoreCase("title")) {
+ if (content == null) {
+ return;
+ }
+
+ if (inItem) {
+ lastItem.title = content.toString();
+ } else if (inImage) {
+ channel.imageTitle = content.toString();
+ } else if (inChannel) {
+ channel.title = content.toString();
+ }
+
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("description")) {
+ if (content == null) {
+ return;
+ }
+
+ if (inItem) {
+ lastItem.description = content.toString();
+ } else if (inImage) {
+ channel.imageDescription = content.toString();
+ } else if (inChannel) {
+ channel.description = content.toString();
+ }
+
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("link")) {
+ if (content == null) {
+ return;
+ }
+
+ if (inItem) {
+ lastItem.link = content.toString();
+ } else if (inImage) {
+ channel.imageLink = content.toString();
+ } else if (inChannel) {
+ channel.link = content.toString();
+ }
+
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("category")) {
+ if (content == null) {
+ return;
+ }
+
+ if (inItem) {
+ lastItem.category = content.toString();
+ } else if (inChannel) {
+ channel.category = content.toString();
+ }
+
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("pubDate")) {
+ if (content == null) {
+ return;
+ }
+
+ if (inItem) {
+ lastItem.pubDate = content.toString();
+ } else if (inChannel) {
+ channel.pubDate = content.toString();
+ }
+
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("guid")) {
+ if (content == null) {
+ return;
+ }
+
+ lastItem.guid = content.toString();
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("url")) {
+ if (content == null) {
+ return;
+ }
+
+ channel.imageUrl = content.toString();
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("width")) {
+ if (content == null) {
+ return;
+ }
+
+ channel.imageWidth = content.toString();
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("height")) {
+ if (content == null) {
+ return;
+ }
+
+ channel.imageHeight = content.toString();
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("language")) {
+ if (content == null) {
+ return;
+ }
+
+ channel.language = content.toString();
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("copyright")) {
+ if (content == null) {
+ return;
+ }
+
+ channel.copyright = content.toString();
+ content = null;
+ }
+
+ if (localName.equalsIgnoreCase("ttl")) {
+ if (content == null) {
+ return;
+ }
+
+ channel.ttl = content.toString();
+ content = null;
+ }
+ }
+
+
+ @Override
+ public void characters(char[] ch, int start, int length) throws SAXException {
+ if (content == null) {
+ return;
+ }
+
+ content.append(ch, start, length);
+ }
+
+
+ public Item getItem(int index) {
+ return items.get(index);
+ }
+} \ No newline at end of file
diff --git a/app/src/main/java/com/camilstaps/taize/Bible.java b/app/src/main/java/com/camilstaps/taize/Bible.java
new file mode 100644
index 0000000..451c7cb
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/taize/Bible.java
@@ -0,0 +1,86 @@
+package com.camilstaps.taize;
+
+import android.content.Context;
+import android.preference.PreferenceManager;
+
+import com.android.volley.Request;
+import com.android.volley.RequestQueue;
+import com.android.volley.Response;
+import com.android.volley.toolbox.StringRequest;
+import com.android.volley.toolbox.Volley;
+
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.net.URLEncoder;
+import java.util.Iterator;
+
+/**
+ * Use the Bible API of getbible.net
+ *
+ * @author Camil Staps
+ */
+public class Bible {
+
+ /**
+ * Base URL of the API
+ */
+ private static final String BASE_URL = "https://getbible.net/json?";
+
+ /**
+ * Request data from the API
+ * @param context context to handle from
+ * @param query_string Query string with parameters for the API
+ * @param listener listener; passed on to Volley, for processing the result
+ * @param errorListener errorListener for when some error occurs
+ */
+ private static void request(Context context, String query_string, Response.Listener<String> listener, Response.ErrorListener errorListener) {
+ RequestQueue queue = Volley.newRequestQueue(context);
+ StringRequest request = new StringRequest(Request.Method.GET, BASE_URL + "v=" + getVersion(context) + "&" + query_string, listener, errorListener);
+ queue.add(request);
+ }
+
+ /**
+ * Get the Bible version (i.e., the translation) from the preferences of the user
+ * @param context context to handle from
+ * @return the version from the preferences
+ */
+ public static String getVersion(Context context) {
+ return PreferenceManager.getDefaultSharedPreferences(context).getString(SettingsActivity.SettingsFragment.PREF_VERSION_BIBLE, context.getResources().getString(R.string.pref_version_bible_default));
+ }
+
+ /**
+ * Get a passage from the API
+ * @param context context to handle from
+ * @param passage indicator for the passage, using English full book names (i.e. "Mark 7:13-18")
+ * @param listener listener; passed on to Volley, for processing the result
+ * @param errorListener errorListener for when some error occurs
+ */
+ public static void getPassage(Context context, String passage, final Response.Listener<String> listener, final Response.ErrorListener errorListener) {
+ request(context, "p=" + URLEncoder.encode(passage), new Response.Listener<String>() {
+ @Override
+ public void onResponse(String s) {
+ StringBuilder passage = new StringBuilder();
+ try {
+ JSONObject response = new JSONObject(s.substring( 1, s.length() - 2));
+ JSONArray books = response.getJSONArray("book");
+ for (int b = 0; b < books.length(); b++) {
+ JSONObject chapter = books.getJSONObject(b).getJSONObject("chapter");
+ Iterator<?> verses = chapter.keys();
+ while (verses.hasNext()) {
+ String verse_number = (String) verses.next();
+ JSONObject verse = chapter.getJSONObject(verse_number);
+ passage.append(verse.getString("verse")).append(" ");
+ }
+ }
+ } catch (JSONException e) {
+ passage.append("No Bible text found.");
+ }
+
+ listener.onResponse(passage.toString());
+ }
+ }, errorListener);
+ }
+
+}
diff --git a/app/src/main/java/com/camilstaps/taize/BibleText.java b/app/src/main/java/com/camilstaps/taize/BibleText.java
new file mode 100644
index 0000000..db73a78
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/taize/BibleText.java
@@ -0,0 +1,73 @@
+package com.camilstaps.taize;
+
+import android.content.Context;
+
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+
+/**
+ * Class for holding some text in the Bible
+ *
+ * @author Camil Staps
+ */
+public class BibleText {
+
+ private String book;
+ private int start_chap, end_chap, start_verse, end_verse;
+
+ /**
+ * Constructor for a bible text consisting of a single verse
+ * @param book
+ * @param chapter
+ * @param verse
+ */
+ public BibleText(String book, int chapter, int verse) {
+ this.book = book;
+ start_chap = end_chap = chapter;
+ start_verse = end_verse = verse;
+ }
+
+ /**
+ * Constructor for a bible text consisting of a "verse range"
+ * @param book
+ * @param start_chap
+ * @param start_verse
+ * @param end_chap
+ * @param end_verse
+ */
+ public BibleText(String book, int start_chap, int start_verse, int end_chap, int end_verse) {
+ this.book = book;
+ this.start_chap = start_chap;
+ this.end_chap = end_chap;
+ this.start_verse = start_verse;
+ this.end_verse = end_verse;
+ }
+
+ /**
+ * Get the text (without verse numbers, line breaks, etc.) of this passage
+ * @param context
+ * @param listener
+ * @param errorListener
+ */
+ public void getText(Context context, Response.Listener<String> listener, Response.ErrorListener errorListener) {
+ String passage = "";
+
+ if (start_chap == end_chap) {
+ if (start_verse == end_verse) {
+ passage = book + " " + start_chap + ":" + start_verse;
+ } else {
+ passage = book + " " + start_chap + ":" + start_verse + "-" + end_verse;
+ }
+ } else {
+ StringBuilder passageBuilder = new StringBuilder();
+ passageBuilder.append(book + " " + start_chap + ":" + start_verse);
+ for (int i = start_chap + 1; i <= end_chap; i++)
+ passageBuilder.append(";" + i);
+ passageBuilder.append("-" + end_verse);
+ passage = passageBuilder.toString();
+ }
+
+ Bible.getPassage(context, passage, listener, errorListener);
+ }
+
+}
diff --git a/app/src/main/java/com/camilstaps/taize/MainActivity.java b/app/src/main/java/com/camilstaps/taize/MainActivity.java
new file mode 100644
index 0000000..b3bf748
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/taize/MainActivity.java
@@ -0,0 +1,165 @@
+package com.camilstaps.taize;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.support.v7.app.ActionBarActivity;
+import android.support.v7.app.ActionBar;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.support.v4.widget.DrawerLayout;
+import android.widget.TextView;
+
+
+public class MainActivity extends ActionBarActivity
+ implements NavigationDrawerFragment.NavigationDrawerCallbacks {
+
+ /**
+ * Fragment managing the behaviors, interactions and presentation of the navigation drawer.
+ */
+ private NavigationDrawerFragment mNavigationDrawerFragment;
+
+ /**
+ * Used to store the last screen title. For use in {@link #restoreActionBar()}.
+ */
+ private CharSequence mTitle;
+
+ private String reading;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ mNavigationDrawerFragment = (NavigationDrawerFragment)
+ 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 onSaveInstanceState(Bundle savedInstanceState) {
+ super.onSaveInstanceState(savedInstanceState);
+ savedInstanceState.putString("textview_dailyreading", ((TextView) findViewById(R.id.textDailyReading)).getText().toString());
+ }
+
+ @Override
+ public void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ ((TextView) findViewById(R.id.textDailyReading)).setText(savedInstanceState.getString("textview_dailyreading"));
+ }
+
+ @Override
+ public void onNavigationDrawerItemSelected(int position) {
+ // update the main content by replacing fragments
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ fragmentManager.beginTransaction()
+ .replace(R.id.container, PlaceholderFragment.newInstance(position + 1))
+ .commit();
+ }
+
+ public void onSectionAttached(int number) {
+ switch (number) {
+ case 1:
+ mTitle = getString(R.string.title_section1);
+ break;
+ case 2:
+ mTitle = getString(R.string.title_section2);
+ break;
+ }
+ }
+
+ 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();
+
+ //noinspection SimplifiableIfStatement
+ if (id == R.id.action_settings) {
+ Intent intent = new Intent(this, SettingsActivity.class);
+ startActivity(intent);
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * A placeholder fragment containing a simple view.
+ */
+ public static class PlaceholderFragment extends Fragment {
+ /**
+ * The fragment argument representing the section number for this
+ * fragment.
+ */
+ private static final String ARG_SECTION_NUMBER = "section_number";
+
+ /**
+ * Returns a new instance of this fragment for the given section
+ * number.
+ */
+ public static PlaceholderFragment newInstance(int sectionNumber) {
+ PlaceholderFragment fragment = new PlaceholderFragment();
+ Bundle args = new Bundle();
+ args.putInt(ARG_SECTION_NUMBER, sectionNumber);
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ public PlaceholderFragment() {
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ View rootView = inflater.inflate(R.layout.fragment_main, container, false);
+
+ return rootView;
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ ((MainActivity) activity).onSectionAttached(getArguments().getInt(ARG_SECTION_NUMBER));
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/camilstaps/taize/NavigationDrawerFragment.java b/app/src/main/java/com/camilstaps/taize/NavigationDrawerFragment.java
new file mode 100644
index 0000000..3bb1556
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/taize/NavigationDrawerFragment.java
@@ -0,0 +1,317 @@
+package com.camilstaps.taize;
+
+import android.support.v7.app.ActionBarActivity;
+import android.app.Activity;
+import android.support.v7.app.ActionBar;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.ActionBarDrawerToggle;
+import android.support.v4.view.GravityCompat;
+import android.support.v4.widget.DrawerLayout;
+import android.content.SharedPreferences;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.text.Html;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.TextView;
+
+import com.android.volley.VolleyError;
+import com.camilstaps.common.Listener;
+
+/**
+ * Fragment used for managing interactions for and presentation of a navigation drawer.
+ * See the <a href="https://developer.android.com/design/patterns/navigation-drawer.html#Interaction">
+ * design guidelines</a> for a complete explanation of the behaviors implemented here.
+ */
+public class NavigationDrawerFragment extends Fragment {
+
+ /**
+ * Remember the position of the selected item.
+ */
+ private static final String STATE_SELECTED_POSITION = "selected_navigation_drawer_position";
+
+ /**
+ * Per the design guidelines, you should show the drawer on launch until the user manually
+ * expands it. This shared preference tracks this.
+ */
+ private static final String PREF_USER_LEARNED_DRAWER = "navigation_drawer_learned";
+
+ /**
+ * A pointer to the current callbacks instance (the Activity).
+ */
+ private NavigationDrawerCallbacks mCallbacks;
+
+ /**
+ * Helper component that ties the action bar to the navigation drawer.
+ */
+ private ActionBarDrawerToggle mDrawerToggle;
+
+ private DrawerLayout mDrawerLayout;
+ private ListView mDrawerListView;
+ private View mFragmentContainerView;
+
+ private int mCurrentSelectedPosition = 0;
+ private boolean mFromSavedInstanceState;
+ private boolean mUserLearnedDrawer;
+
+ public NavigationDrawerFragment() {
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Read in the flag indicating whether or not the user has demonstrated awareness of the
+ // drawer. See PREF_USER_LEARNED_DRAWER for details.
+ SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getActivity());
+ mUserLearnedDrawer = sp.getBoolean(PREF_USER_LEARNED_DRAWER, false);
+
+ if (savedInstanceState != null) {
+ mCurrentSelectedPosition = savedInstanceState.getInt(STATE_SELECTED_POSITION);
+ mFromSavedInstanceState = true;
+ }
+
+ // Select either the default item (0) or the last selected item.
+ selectItem(mCurrentSelectedPosition);
+ }
+
+ @Override
+ public void onActivityCreated(Bundle savedInstanceState) {
+ super.onActivityCreated(savedInstanceState);
+ // Indicate that this fragment would like to influence the set of actions in the action bar.
+ setHasOptionsMenu(true);
+ }
+
+ @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<String>(
+ 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),
+ }));
+ mDrawerListView.setItemChecked(mCurrentSelectedPosition, true);
+ return mDrawerListView;
+ }
+
+ public boolean isDrawerOpen() {
+ return mDrawerLayout != null && mDrawerLayout.isDrawerOpen(mFragmentContainerView);
+ }
+
+ /**
+ * Users of this fragment must call this method to set up the navigation drawer interactions.
+ *
+ * @param fragmentId The android:id of this fragment in its activity's layout.
+ * @param drawerLayout The DrawerLayout containing this fragment's UI.
+ */
+ public void setUp(int fragmentId, DrawerLayout drawerLayout) {
+ mFragmentContainerView = getActivity().findViewById(fragmentId);
+ mDrawerLayout = drawerLayout;
+
+ // set a custom shadow that overlays the main content when the drawer opens
+ mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
+ // set up the drawer's list view with items and click listener
+
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeButtonEnabled(true);
+
+ // ActionBarDrawerToggle ties together the the proper interactions
+ // between the navigation drawer and the action bar app icon.
+ mDrawerToggle = new ActionBarDrawerToggle(
+ getActivity(), /* host Activity */
+ mDrawerLayout, /* DrawerLayout object */
+ R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
+ R.string.navigation_drawer_open, /* "open drawer" description for accessibility */
+ R.string.navigation_drawer_close /* "close drawer" description for accessibility */
+ ) {
+ @Override
+ public void onDrawerClosed(View drawerView) {
+ super.onDrawerClosed(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+
+ getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
+ }
+
+ @Override
+ public void onDrawerOpened(View drawerView) {
+ super.onDrawerOpened(drawerView);
+ if (!isAdded()) {
+ return;
+ }
+
+ if (!mUserLearnedDrawer) {
+ // The user manually opened the drawer; store this flag to prevent auto-showing
+ // the navigation drawer automatically in the future.
+ mUserLearnedDrawer = true;
+ SharedPreferences sp = PreferenceManager
+ .getDefaultSharedPreferences(getActivity());
+ sp.edit().putBoolean(PREF_USER_LEARNED_DRAWER, true).apply();
+ }
+
+ getActivity().supportInvalidateOptionsMenu(); // calls onPrepareOptionsMenu()
+ }
+ };
+
+ // If the user hasn't 'learned' about the drawer, open it to introduce them to the drawer,
+ // per the navigation drawer design guidelines.
+ if (!mUserLearnedDrawer && !mFromSavedInstanceState) {
+ mDrawerLayout.openDrawer(mFragmentContainerView);
+ }
+
+ // Defer code dependent on restoration of previous instance state.
+ mDrawerLayout.post(new Runnable() {
+ @Override
+ public void run() {
+ mDrawerToggle.syncState();
+ }
+ });
+
+ mDrawerLayout.setDrawerListener(mDrawerToggle);
+ }
+
+ private void selectItem(int position) {
+ mCurrentSelectedPosition = position;
+ if (mDrawerListView != null) {
+ mDrawerListView.setItemChecked(position, true);
+ }
+ if (mDrawerLayout != null) {
+ mDrawerLayout.closeDrawer(mFragmentContainerView);
+ }
+ if (mCallbacks != null) {
+ mCallbacks.onNavigationDrawerItemSelected(position);
+ }
+ }
+
+ @Override
+ public void onAttach(Activity activity) {
+ super.onAttach(activity);
+ try {
+ mCallbacks = (NavigationDrawerCallbacks) activity;
+ } catch (ClassCastException e) {
+ throw new ClassCastException("Activity must implement NavigationDrawerCallbacks.");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ mCallbacks = null;
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(STATE_SELECTED_POSITION, mCurrentSelectedPosition);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newConfig) {
+ super.onConfigurationChanged(newConfig);
+ // Forward the new configuration the drawer toggle component.
+ mDrawerToggle.onConfigurationChanged(newConfig);
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ // If the drawer is open, show the global app actions in the action bar. See also
+ // showGlobalContextActionBar, which controls the top-left area of the action bar.
+ if (mDrawerLayout != null && isDrawerOpen()) {
+ inflater.inflate(R.menu.global, menu);
+ showGlobalContextActionBar();
+ }
+ super.onCreateOptionsMenu(menu, inflater);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (mDrawerToggle.onOptionsItemSelected(item)) {
+ return true;
+ }
+
+ if (item.getItemId() == R.id.action_update) {
+ //Toast.makeText(getActivity(), "Example action.", Toast.LENGTH_SHORT).show();
+
+ final TextView reading = (TextView) getActivity().findViewById(R.id.textDailyReading);
+
+ Taize.getDailyReading(getActivity(), new Listener<String>() {
+ @Override
+ public void success(String data) {
+ reading.setText(Html.fromHtml(data));
+ }
+
+ @Override
+ public void failure() {
+ reading.setText("Error fetching reading.");
+ }
+ });
+
+ reading.append("\n\n");
+
+ Taize.getDailyReadingBibleText(getActivity(), new Listener<String>() {
+ @Override
+ public void success(String data) {
+ Log.i("LOG", "Success.");
+ Log.i("LOG", data);
+ reading.append(Html.fromHtml(data));
+ }
+
+ @Override
+ public void failure() {
+ Log.i("LOG", "Failure.");
+ }
+ });
+
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ /**
+ * Per the navigation drawer design guidelines, updates the action bar to show the global app
+ * 'context', rather than just what's in the current screen.
+ */
+ private void showGlobalContextActionBar() {
+ ActionBar actionBar = getActionBar();
+ actionBar.setDisplayShowTitleEnabled(true);
+ actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
+ actionBar.setTitle(R.string.app_name);
+ }
+
+ private ActionBar getActionBar() {
+ return ((ActionBarActivity) getActivity()).getSupportActionBar();
+ }
+
+ /**
+ * Callbacks interface that all activities using this fragment must implement.
+ */
+ public static interface NavigationDrawerCallbacks {
+ /**
+ * Called when an item in the navigation drawer is selected.
+ */
+ void onNavigationDrawerItemSelected(int position);
+ }
+}
diff --git a/app/src/main/java/com/camilstaps/taize/SettingsActivity.java b/app/src/main/java/com/camilstaps/taize/SettingsActivity.java
new file mode 100644
index 0000000..c8f3b3d
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/taize/SettingsActivity.java
@@ -0,0 +1,66 @@
+package com.camilstaps.taize;
+
+
+import android.os.Bundle;
+import android.preference.ListPreference;
+import android.preference.Preference;
+import android.preference.PreferenceActivity;
+import android.preference.PreferenceFragment;
+import android.preference.PreferenceManager;
+
+import com.camilstaps.common.NullListener;
+
+public class SettingsActivity extends PreferenceActivity {
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
+ }
+
+ private static Preference.OnPreferenceChangeListener onPreferenceChangeListener = new Preference.OnPreferenceChangeListener() {
+ @Override
+ public boolean onPreferenceChange(Preference pref, Object newValue) {
+ String stringValue = newValue.toString();
+
+ if (pref instanceof ListPreference) {
+ ListPreference listPref = (ListPreference) pref;
+ int index = listPref.findIndexOfValue(stringValue);
+ pref.setSummary(index >= 0 ? listPref.getEntries()[index] : null); // .getEntry() seems to cause problems
+ } else {
+ pref.setSummary(stringValue);
+ }
+
+ // If the preference actually changed ...
+ if (!PreferenceManager.getDefaultSharedPreferences(pref.getContext()).getString(pref.getKey(), "").equals(stringValue)) {
+ if (pref.getKey().equals(SettingsFragment.PREF_LANGUAGE_READINGS)) { // If we select a new language, set the fetch time to 0 to refetch on next request
+ Taize.forceNewDailyReading(pref.getContext(), new NullListener<String>());
+ } else if (pref.getKey().equals(SettingsFragment.PREF_VERSION_BIBLE)) { // If we select a new bible, set the fetch time to 0 to refetch on next request
+ Taize.forceNewDailyReadingBibleText(pref.getContext(), new NullListener<String>());
+ }
+ }
+
+ return true;
+ }
+ };
+
+ private static void bindSummaryToValue(Preference pref) {
+ pref.setOnPreferenceChangeListener(onPreferenceChangeListener);
+ onPreferenceChangeListener.onPreferenceChange(pref, PreferenceManager.getDefaultSharedPreferences(pref.getContext()).getString(pref.getKey(), pref.getSummary().toString()));
+ }
+
+ public static class SettingsFragment extends PreferenceFragment {
+ public static final String PREF_LANGUAGE_READINGS = "pref_language_reading";
+ public static final String PREF_VERSION_BIBLE = "pref_version_bible";
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.preferences);
+
+ bindSummaryToValue(findPreference(PREF_LANGUAGE_READINGS));
+ bindSummaryToValue(findPreference(PREF_VERSION_BIBLE));
+ }
+ }
+
+}
diff --git a/app/src/main/java/com/camilstaps/taize/Taize.java b/app/src/main/java/com/camilstaps/taize/Taize.java
new file mode 100644
index 0000000..edfe9e7
--- /dev/null
+++ b/app/src/main/java/com/camilstaps/taize/Taize.java
@@ -0,0 +1,224 @@
+package com.camilstaps.taize;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.util.Log;
+
+import com.android.volley.Response;
+import com.android.volley.VolleyError;
+import com.camilstaps.common.Listener;
+import com.camilstaps.common.NullListener;
+import com.camilstaps.rss.RetrieveFeedTask;
+import com.camilstaps.rss.RssParser;
+
+import java.util.concurrent.ExecutionException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Class specific to methods for Taize
+ * @author Camil Staps
+ */
+public class Taize {
+
+ private static final String url_reading_feed = "http://www.taize.fr/readingrss.php";
+ private static final String url_reading_feed_en = "http://www.taize.fr/readingrss.php?lang=en";
+
+ /**
+ * Force fetching a new bible text for the daily reading
+ * @see this#getDailyReadingBibleText
+ * @param context
+ * @param listener
+ */
+ public static void forceNewDailyReadingBibleText(final Context context, final Listener<String> listener) {
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putLong("dailyreadingbiblefetch", 0);
+ editor.putLong("englishdailyreadingfetch", 0);
+ editor.commit();
+ getDailyReadingBibleText(context, listener);
+ }
+
+ /**
+ * Fetch the bible text corresponding to the daily reading
+ * @see this#forceNewDailyReadingBibleText
+ * @param context
+ * @param listener
+ */
+ public static void getDailyReadingBibleText(final Context context, final Listener<String> listener) {
+ if (System.currentTimeMillis() - PreferenceManager.getDefaultSharedPreferences(context).getLong("dailyreadingbiblefetch", 0) > 3600000) {
+
+ getEnglishDailyReading(context, new Listener<String>() {
+ @Override
+ public void success(String reading) {
+
+ Log.i("LOG", "Matching: " + reading);
+
+ Pattern bible_ref = Pattern.compile("\\((\\d? ?[a-zA-Z]+) (\\d{1,2}):(\\d+)-?(\\d+?)\\)");
+ Matcher bible_ref_m = bible_ref.matcher(reading);
+
+ if (!bible_ref_m.find()) {
+ failure();
+ return;
+ }
+
+ BibleText text = new BibleText(bible_ref_m.group(1), Integer.parseInt(bible_ref_m.group(2)), Integer.parseInt(bible_ref_m.group(3)), Integer.parseInt(bible_ref_m.group(2)), Integer.parseInt(bible_ref_m.group(4)));
+
+ text.getText(context, new Response.Listener<String>() {
+ @Override
+ public void onResponse(String s) {
+ Log.i("LOG", "Bible text: " + s);
+ PreferenceManager.getDefaultSharedPreferences(context).edit().putString("dailyreadingbible", s).apply();
+ listener.success(s);
+ }
+ }, new Response.ErrorListener() {
+ @Override
+ public void onErrorResponse(VolleyError volleyError) {
+ Log.e("NET", "Failed to fetch bible text.");
+ }
+ });
+
+ }
+
+ @Override
+ public void failure() {
+ listener.failure();
+ }
+ });
+
+ PreferenceManager.getDefaultSharedPreferences(context).edit().putLong("dailyreadingbiblefetch", System.currentTimeMillis()).apply();
+
+ } else {
+
+ listener.success(PreferenceManager.getDefaultSharedPreferences(context).getString("dailyreadingbible", "No bible text found."));
+
+ }
+ }
+
+ /**
+ * Force fetching a new English daily reading
+ * @see this#getEnglishDailyReading
+ * @param context
+ * @param listener
+ */
+ private static void forceNewEnglishDailyReading(final Context context, final Listener<String> listener) {
+ PreferenceManager.getDefaultSharedPreferences(context).edit().putLong("englishdailyreadingfetch", 0).commit();
+ getEnglishDailyReading(context, listener);
+ }
+
+ /**
+ * Get the English daily reading (needed for the English Bible reference)
+ * @see this#forceNewEnglishDailyReading
+ * @param context
+ * @param listener
+ */
+ private static void getEnglishDailyReading(final Context context, final Listener<String> listener) {
+ if (System.currentTimeMillis() - PreferenceManager.getDefaultSharedPreferences(context).getLong("englishdailyreadingfetch", 0) > 3600000) {
+
+ RetrieveFeedTask retrieve = new RetrieveFeedTask();
+ retrieve.setRssDownloadListener(new Listener<RssParser>() {
+ @Override
+ public void success(RssParser parser) {
+ try {
+ String reading = parser.getItem(0).description.trim();
+
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putString("englishdailyreading", reading);
+ editor.putLong("englishdailyreadingfetch", System.currentTimeMillis());
+ editor.apply();
+
+ listener.success(reading);
+ } catch (Exception e) {
+ failure();
+ }
+ }
+
+ @Override
+ public void failure() {
+ Log.i("LOG", "Failed to update.");
+ listener.failure();
+ }
+ });
+
+ try {
+ retrieve.execute(url_reading_feed_en).get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ } else {
+
+ listener.success(PreferenceManager.getDefaultSharedPreferences(context).getString("englishdailyreading", "No daily reading found."));
+
+ }
+ }
+
+ /**
+ * Force fetching a new daily reading
+ * @see this#getDailyReading
+ * @param context
+ * @param listener
+ */
+ public static void forceNewDailyReading(final Context context, final Listener<String> listener) {
+ PreferenceManager.getDefaultSharedPreferences(context).edit().putLong("dailyreadingfetch", 0).commit();
+ getDailyReading(context, listener);
+ }
+
+ /**
+ * Fetch the daily reading
+ * @see this#forceNewDailyReading
+ * @param context
+ * @param listener
+ */
+ public static void getDailyReading(final Context context, final Listener<String> listener) {
+ if (System.currentTimeMillis() - PreferenceManager.getDefaultSharedPreferences(context).getLong("dailyreadingfetch", 0) > 3600000) {
+
+ RetrieveFeedTask retrieve = new RetrieveFeedTask();
+ retrieve.setRssDownloadListener(new Listener<RssParser>() {
+ @Override
+ public void success(RssParser parser) {
+ try {
+ String reading = parser.getItem(0).description.trim();
+
+ if (!reading.equals(PreferenceManager.getDefaultSharedPreferences(context).getString("dailyreading", ""))) {
+ forceNewDailyReadingBibleText(context, new NullListener<String>());
+ }
+
+ SharedPreferences.Editor editor = PreferenceManager.getDefaultSharedPreferences(context).edit();
+ editor.putString("dailyreading", reading);
+ editor.putLong("dailyreadingfetch", System.currentTimeMillis());
+ editor.apply();
+
+ listener.success(reading);
+ } catch (Exception e) {
+ failure();
+ }
+ }
+
+ @Override
+ public void failure() {
+ Log.i("LOG", "Failed to update.");
+ listener.failure();
+ }
+ });
+
+ try {
+ retrieve.execute(url_reading_feed + "?lang=" + PreferenceManager.getDefaultSharedPreferences(context).getString(SettingsActivity.SettingsFragment.PREF_LANGUAGE_READINGS, "en")).get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+
+ } else {
+
+ listener.success(PreferenceManager.getDefaultSharedPreferences(context).getString("dailyreading", "No daily reading found."));
+
+ }
+ }
+
+ //http://www.taize.fr/pdcrss.xml
+
+}
diff --git a/app/src/main/res/drawable-hdpi/drawer_shadow.9.png b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..236bff5
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/drawer_shadow.9.png
Binary files differ
diff --git a/app/src/main/res/drawable-hdpi/ic_drawer.png b/app/src/main/res/drawable-hdpi/ic_drawer.png
new file mode 100644
index 0000000..c59f601
--- /dev/null
+++ b/app/src/main/res/drawable-hdpi/ic_drawer.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/drawer_shadow.9.png b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..ffe3a28
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/drawer_shadow.9.png
Binary files differ
diff --git a/app/src/main/res/drawable-mdpi/ic_drawer.png b/app/src/main/res/drawable-mdpi/ic_drawer.png
new file mode 100644
index 0000000..1ed2c56
--- /dev/null
+++ b/app/src/main/res/drawable-mdpi/ic_drawer.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..fabe9d9
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/drawer_shadow.9.png
Binary files differ
diff --git a/app/src/main/res/drawable-xhdpi/ic_drawer.png b/app/src/main/res/drawable-xhdpi/ic_drawer.png
new file mode 100644
index 0000000..a5fa74d
--- /dev/null
+++ b/app/src/main/res/drawable-xhdpi/ic_drawer.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png
new file mode 100644
index 0000000..b91e9d7
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/drawer_shadow.9.png
Binary files differ
diff --git a/app/src/main/res/drawable-xxhdpi/ic_drawer.png b/app/src/main/res/drawable-xxhdpi/ic_drawer.png
new file mode 100644
index 0000000..9c4685d
--- /dev/null
+++ b/app/src/main/res/drawable-xxhdpi/ic_drawer.png
Binary files differ
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..17ea429
--- /dev/null
+++ b/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,40 @@
+<!-- A DrawerLayout is intended to be used as the top-level content view using match_parent for both width and height to consume the full space available. -->
+<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/drawer_layout"
+ android:layout_width="match_parent" android:layout_height="match_parent"
+ tools:context=".MainActivity">
+
+ <!-- As the main content view, the view below consumes the entire
+ space available using match_parent in both dimensions. -->
+ <FrameLayout android:id="@+id/container" android:layout_width="match_parent"
+ android:layout_height="match_parent" >
+
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:fillViewport="true">
+
+ <TextView
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:text="Daily Reading"
+ android:id="@+id/textDailyReading"
+ android:layout_gravity="left|top"
+ android:layout_weight="1.0"/>
+
+ </ScrollView>
+ </FrameLayout>
+
+ <!-- android:layout_gravity="start" tells DrawerLayout to treat
+ this as a sliding drawer on the left side for left-to-right
+ languages and on the right side for right-to-left languages.
+ If you're not building against API 17 or higher, use
+ android:layout_gravity="left" instead. -->
+ <!-- The drawer is given a fixed width in dp and extends the full height of
+ the container. -->
+ <fragment android:id="@+id/navigation_drawer"
+ android:layout_width="@dimen/navigation_drawer_width" android:layout_height="match_parent"
+ android:layout_gravity="start" android:name="com.camilstaps.taize.NavigationDrawerFragment"
+ tools:layout="@layout/fragment_navigation_drawer" />
+
+</android.support.v4.widget.DrawerLayout>
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
new file mode 100644
index 0000000..ef0bd84
--- /dev/null
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -0,0 +1,12 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+ android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
+ android:paddingRight="@dimen/activity_horizontal_margin"
+ android:paddingTop="@dimen/activity_vertical_margin"
+ android:paddingBottom="@dimen/activity_vertical_margin"
+ tools:context=".MainActivity$PlaceholderFragment">
+
+ <TextView android:id="@+id/section_label" android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</RelativeLayout>
diff --git a/app/src/main/res/layout/fragment_navigation_drawer.xml b/app/src/main/res/layout/fragment_navigation_drawer.xml
new file mode 100644
index 0000000..c05742d
--- /dev/null
+++ b/app/src/main/res/layout/fragment_navigation_drawer.xml
@@ -0,0 +1,5 @@
+<ListView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+ android:layout_height="match_parent" android:choiceMode="singleChoice"
+ android:divider="@android:color/transparent" android:dividerHeight="0dp"
+ android:background="#cccc" tools:context=".NavigationDrawerFragment" />
diff --git a/app/src/main/res/menu/global.xml b/app/src/main/res/menu/global.xml
new file mode 100644
index 0000000..326a6a7
--- /dev/null
+++ b/app/src/main/res/menu/global.xml
@@ -0,0 +1,5 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto">
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" app:showAsAction="never" />
+</menu>
diff --git a/app/src/main/res/menu/main.xml b/app/src/main/res/menu/main.xml
new file mode 100644
index 0000000..1ee42b7
--- /dev/null
+++ b/app/src/main/res/menu/main.xml
@@ -0,0 +1,8 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
+ <item android:id="@+id/action_update" android:title="@string/action_example"
+ app:showAsAction="withText|ifRoom" />
+ <item android:id="@+id/action_settings" android:title="@string/action_settings"
+ android:orderInCategory="100" app:showAsAction="never" />
+</menu>
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 0000000..cde69bc
--- /dev/null
+++ b/app/src/main/res/mipmap-hdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 0000000..c133a0c
--- /dev/null
+++ b/app/src/main/res/mipmap-mdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..bfa42f0
--- /dev/null
+++ b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 0000000..324e72c
--- /dev/null
+++ b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
Binary files differ
diff --git a/app/src/main/res/values-w820dp/dimens.xml b/app/src/main/res/values-w820dp/dimens.xml
new file mode 100644
index 0000000..63fc816
--- /dev/null
+++ b/app/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@
+<resources>
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+ (such as screen margins) for screens with more than 820dp of available width. This
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+ <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>
diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml
new file mode 100644
index 0000000..074e7a0
--- /dev/null
+++ b/app/src/main/res/values/dimens.xml
@@ -0,0 +1,9 @@
+<resources>
+ <!-- Default screen margins, per the Android Design guidelines. -->
+ <dimen name="activity_horizontal_margin">16dp</dimen>
+ <dimen name="activity_vertical_margin">16dp</dimen>
+
+ <!-- Per the design guidelines, navigation drawers should be between 240dp and 320dp:
+ https://developer.android.com/design/patterns/navigation-drawer.html -->
+ <dimen name="navigation_drawer_width">240dp</dimen>
+</resources>
diff --git a/app/src/main/res/values/preference_values.xml b/app/src/main/res/values/preference_values.xml
new file mode 100644
index 0000000..754ec9e
--- /dev/null
+++ b/app/src/main/res/values/preference_values.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="title_activity_settings">Settings</string>
+
+ <!-- Strings related to Settings -->
+ <string name="pref_title_language_dailyreading">Language of the readings</string>
+ <string name="pref_language_dailyreading_default">en</string>
+ <string name="pref_language_dailyreading_default_entry">English</string>
+ <string-array name="pref_languages_dailyreading_entries">
+ <item>English</item>
+ <item>čeština</item>
+ <item>dansk</item>
+ <item>Deutsch</item>
+ <item>Español</item>
+ <item>eesti</item>
+ <item>suomi</item>
+ <item>français</item>
+ <item>hrvatski</item>
+ <item>magyar</item>
+ <item>Indonesia</item>
+ <item>italiano</item>
+ <item>日本語</item>
+ <item>한국어</item>
+ <item>lietuvių</item>
+ <item>Nederlands</item>
+ <item>norsk</item>
+ <item>polski</item>
+ <item>Português</item>
+ <item>русский</item>
+ <item>slovenčina</item>
+ <item>slovenščina</item>
+ <item>svenska</item>
+ <item>中文</item>
+ </string-array>
+ <string-array name="pref_languages_dailyreading_values">
+ <item>en</item>
+ <item>cs</item>
+ <item>da</item>
+ <item>de</item>
+ <item>es</item>
+ <item>et</item>
+ <item>fi</item>
+ <item>fr</item>
+ <item>hr</item>
+ <item>hu</item>
+ <item>id</item>
+ <item>it</item>
+ <item>ja</item>
+ <item>ko</item>
+ <item>lt</item>
+ <item>nl</item>
+ <item>no</item>
+ <item>pl</item>
+ <item>pt</item>
+ <item>ru</item>
+ <item>sk</item>
+ <item>sl</item>
+ <item>sv</item>
+ <item>zh</item>
+ </string-array>
+
+ <string name="pref_title_version_bible">Bible</string>
+ <string name="pref_version_bible_default">kjv</string>
+ <string name="pref_version_bible_default_entry">King James Version</string>
+ <string-array name="pref_bibles_entries">
+ <item>Afrikaans: Ou Vertaling</item>
+ <item>Albanian: Albanian</item>
+ <item>Amharic: Haile Selassie Amharic Bible</item>
+ <item>Arabic: Smith and Van Dyke</item>
+ <item>Chinese: NCV Traditional</item>
+ <item>Chinese: Union Simplified</item>
+ <item>Chinese: NCV Simplified</item>
+ <item>Chinese: Union Traditional</item>
+ <item>Croatian: Croatian</item>
+ <item>Danish: Danish</item>
+ <item>Dutch: Dutch Staten Vertaling</item>
+ <item>English: King James Version</item>
+ <item>English: KJV Easy Read</item>
+ <item>English: American Standard Version</item>
+ <item>English: Amplified Version</item>
+ <item>English: Basic English Bible</item>
+ <item>English: Darby</item>
+ <item>English: New American Standard</item>
+ <item>English: Young\'s Literal Translation</item>
+ <item>English: World English Bible</item>
+ <item>English: Webster\'s Bible</item>
+ <item>Esperanto: Esperanto</item>
+ <item>Estonian: Estonian</item>
+ <item>Finnish: Finnish Bible</item>
+ <item>French: Martin</item>
+ <item>German: Luther</item>
+ <item>Greek: Greek Modern</item>
+ <item>Greek: Textus Receptus</item>
+ <item>Hebrew: Aleppo Codex</item>
+ <item>Hungarian: Hungarian Karoli</item>
+ <item>Italian: Giovanni Diodati Bible</item>
+ <item>Korean: Korean</item>
+ <item>Norwegian: Bibelselskap</item>
+ <item>Portuguese: Almeida Atualizada</item>
+ <item>Russian: Synodal Translation</item>
+ <item>Spanish: Reina Valera</item>
+ <item>Swahili: Swahili</item>
+ <item>Swedish: Swedish</item>
+ <item>Turkish: Turkish</item>
+ <item>Vietnamese: Vietnamese</item>
+ <item>Xhosa: Xhosa</item>
+ </string-array>
+ <string-array name="pref_bibles_values">
+ <item>aov</item>
+ <item>albanian</item>
+ <item>hsab</item>
+ <item>arabicsv</item>
+ <item>cnt</item>
+ <item>cus</item>
+ <item>cns</item>
+ <item>cut</item>
+ <item>croatia</item>
+ <item>danish</item>
+ <item>statenvertaling</item>
+ <item>kjv</item>
+ <item>akjv</item>
+ <item>asv</item>
+ <item>amp</item>
+ <item>basicenglish</item>
+ <item>darby</item>
+ <item>nasb</item>
+ <item>ylt</item>
+ <item>web</item>
+ <item>wb</item>
+ <item>esperanto</item>
+ <item>estonian</item>
+ <item>finnish1776</item>
+ <item>martin</item>
+ <item>luther1912</item>
+ <item>moderngreek</item>
+ <item>text</item>
+ <item>aleppo</item>
+ <item>karoli</item>
+ <item>giovanni</item>
+ <item>korean</item>
+ <item>bibelselskap</item>
+ <item>almeida</item>
+ <item>synodal</item>
+ <item>valera</item>
+ <item>swahili</item>
+ <item>swedish</item>
+ <item>turkish</item>
+ <item>vietnamese</item>
+ <item>xhosa</item>
+ </string-array>
+
+</resources>
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
new file mode 100644
index 0000000..32383f1
--- /dev/null
+++ b/app/src/main/res/values/strings.xml
@@ -0,0 +1,13 @@
+<resources>
+ <string name="app_name">Taizé</string>
+
+ <string name="title_section1">Daily Reading</string>
+ <string name="title_section2">Daily Meditation</string>
+
+ <string name="navigation_drawer_open">Open navigation drawer</string>
+ <string name="navigation_drawer_close">Close navigation drawer</string>
+
+ <string name="action_example">Update</string>
+
+ <string name="action_settings">Settings</string>
+</resources>
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
new file mode 100644
index 0000000..766ab99
--- /dev/null
+++ b/app/src/main/res/values/styles.xml
@@ -0,0 +1,8 @@
+<resources>
+
+ <!-- Base application theme. -->
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+ <!-- Customize your theme here. -->
+ </style>
+
+</resources>
diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml
new file mode 100644
index 0000000..1525761
--- /dev/null
+++ b/app/src/main/res/xml/preferences.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <PreferenceCategory
+ android:title="@string/title_activity_settings"
+ android:key="preferences_key">
+
+ <ListPreference
+ android:key="pref_language_reading"
+ android:title="@string/pref_title_language_dailyreading"
+ android:entries="@array/pref_languages_dailyreading_entries"
+ android:entryValues="@array/pref_languages_dailyreading_values"
+ android:persistent="true"
+ android:defaultValue="@string/pref_language_dailyreading_default"
+ android:summary="@string/pref_language_dailyreading_default_entry" />
+
+ <ListPreference
+ android:key="pref_version_bible"
+ android:title="@string/pref_title_version_bible"
+ android:entries="@array/pref_bibles_entries"
+ android:entryValues="@array/pref_bibles_values"
+ android:persistent="true"
+ android:defaultValue="@string/pref_version_bible_default"
+ android:summary="@string/pref_version_bible_default_entry" />
+
+ </PreferenceCategory>
+
+</PreferenceScreen> \ No newline at end of file