diff --git a/app/build.gradle b/app/build.gradle
index e583099..adb195a 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -11,6 +11,7 @@ apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'
apply plugin: 'io.fabric'
apply plugin: 'com.github.triplet.play'
+
repositories {
maven { url 'https://maven.fabric.io/public' }
}
@@ -18,21 +19,23 @@ repositories {
android {
- dataBinding { enabled = true}
+ dataBinding { enabled = true }
compileSdkVersion 23
- buildToolsVersion "23.0.2"
+ buildToolsVersion "23.0.3"
defaultConfig {
applicationId "org.bookdash.android"
minSdkVersion 16
targetSdkVersion 23
- versionCode 17
- versionName "1.0.17"
- testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
+ versionCode 18
+ versionName "1.1.0"
+ testInstrumentationRunner "org.bookdash.android.presentation.CustomTestRunner"
buildConfigField "String", "PARSE_APPLICATION_ID", "\"${BOOKDASH_PARSE_APP_ID}\""
buildConfigField "String", "PARSE_CLIENT_KEY", "\"${BOOKDASH_PARSE_CLIENT_ID}\""
+ vectorDrawables.useSupportLibrary = true
}
+
File signFile = rootProject.file('release-keystore.properties')
if (signFile.exists()) {
signingConfigs {
@@ -74,7 +77,7 @@ android {
}
// Remove mockRelease as it's not needed.
android.variantFilter { variant ->
- if(variant.buildType.name.equals('release')
+ if (variant.buildType.name.equals('release')
&& variant.getFlavors().get(0).name.equals('mock')) {
variant.setIgnore(true);
}
@@ -90,7 +93,7 @@ android {
release {
shrinkResources false
minifyEnabled true
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro'
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
ext.enableCrashlytics = true
}
debug {
@@ -110,37 +113,37 @@ dependencies {
testCompile "junit:junit:$rootProject.ext.junitVersion"
testCompile "org.mockito:mockito-all:$rootProject.ext.mockitoVersion"
testCompile "org.hamcrest:hamcrest-all:$rootProject.ext.hamcrestVersion"
- testCompile ("org.powermock:powermock-module-junit4:$rootProject.ext.powerMockito")
- testCompile ("org.powermock:powermock-api-mockito:$rootProject.ext.powerMockito")
+ testCompile("org.powermock:powermock-module-junit4:$rootProject.ext.powerMockito")
+ testCompile("org.powermock:powermock-api-mockito:$rootProject.ext.powerMockito")
// Android Testing Support Library's runner and rules
- androidTestCompile ('com.android.support.test.espresso:espresso-web:2.2.1'){
+ androidTestCompile('com.android.support.test.espresso:espresso-web:2.2.1') {
exclude module: 'support-annotations'
exclude module: 'support-v4'
}
- androidTestCompile ("com.android.support.test:runner:$rootProject.ext.runnerVersion"){
+ androidTestCompile("com.android.support.test:runner:$rootProject.ext.runnerVersion") {
exclude module: 'support-annotations'
exclude module: 'support-v4'
}
- androidTestCompile ("com.android.support.test:rules:$rootProject.ext.runnerVersion"){
+ androidTestCompile("com.android.support.test:rules:$rootProject.ext.runnerVersion") {
exclude module: 'support-annotations'
exclude module: 'support-v4'
}
// Espresso UI Testing
- androidTestCompile ("com.android.support.test.espresso:espresso-core:$rootProject.ext.espressoVersion"){
+ androidTestCompile("com.android.support.test.espresso:espresso-core:$rootProject.ext.espressoVersion") {
exclude module: 'recyclerview-v7'
exclude module: 'support-annotations'
exclude module: 'support-v4'
exclude group: "javax.inject"
}
- androidTestCompile ("com.android.support.test.espresso:espresso-contrib:$rootProject.ext.espressoVersion") {
+ androidTestCompile("com.android.support.test.espresso:espresso-contrib:$rootProject.ext.espressoVersion") {
exclude module: 'recyclerview-v7'
exclude module: 'support-annotations'
exclude module: 'support-v4'
}
- androidTestCompile ("com.android.support.test.espresso:espresso-intents:$rootProject.ext.espressoVersion"){
+ androidTestCompile("com.android.support.test.espresso:espresso-intents:$rootProject.ext.espressoVersion") {
exclude module: 'recyclerview-v7'
exclude module: 'support-annotations'
exclude module: 'support-v4'
@@ -159,8 +162,8 @@ dependencies {
compile 'com.google.code.gson:gson:2.4'
compile 'com.github.castorflex.smoothprogressbar:library-circular:1.2.0'
- // compile 'com.parse.bolts:bolts-android:1.3.0'
- // compile 'com.parse:parse-android:1.11.0'
+ // compile 'com.parse.bolts:bolts-android:1.3.0'
+ // compile 'com.parse:parse-android:1.11.0'
compile('com.crashlytics.sdk.android:crashlytics:2.5.3@aar') {
transitive = true;
}
@@ -170,3 +173,23 @@ dependencies {
compile "com.android.support:design:$rootProject.ext.googlePlayServicesVersion"
compile "com.google.android.gms:play-services-analytics:$rootProject.ext.googlePlayServicesVersion"
}
+
+// Grant animation permissions to avoid test failure because of ui sync.
+task grantAnimationPermissions(type: Exec, dependsOn: 'installMock') {
+ group = 'test'
+ description = 'Grant permissions for testing.'
+
+ def absolutePath = file('..') // Get project absolute path
+ commandLine "$absolutePath/set_animation_permissions.sh org.bookdash.android".split(" ")
+}
+
+// Source: http://stackoverflow.com/q/29908110/112705
+afterEvaluate {
+ // When launching individual tests from Android Studio, it seems that only the assemble tasks
+ // get called directly, not the install* versions
+ tasks.each { task ->
+ if (task.name.startsWith('assembleMockAndroidTest')) {
+ task.dependsOn grantAnimationPermissions
+ }
+ }
+}
diff --git a/app/src/androidTest/java/org/bookdash/android/presentation/CustomTestRunner.java b/app/src/androidTest/java/org/bookdash/android/presentation/CustomTestRunner.java
new file mode 100644
index 0000000..053fcf7
--- /dev/null
+++ b/app/src/androidTest/java/org/bookdash/android/presentation/CustomTestRunner.java
@@ -0,0 +1,104 @@
+package org.bookdash.android.presentation;
+
+import android.Manifest;
+import android.app.KeyguardManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.PowerManager;
+import android.support.test.runner.AndroidJUnitRunner;
+import android.util.Log;
+
+import java.lang.reflect.Method;
+
+/**
+ * Tests can fail for other reasons than code, it´ because of the animations and espresso sync and
+ * emulator state (screen off or locked)
+ *
+ * Before all the tests prepare the device to run tests and avoid these problems.
+ *
+ * - Disable animations
+ * - Disable keyguard lock
+ * - Set it to be awake all the time (dont let the processor sleep)
+ *
+ * @see https://github.com/JakeWharton/u2020
+ * @see https://gist.github.com/daj/7b48f1b8a92abf960e7b
+ */
+public final class CustomTestRunner extends AndroidJUnitRunner {
+
+ private static final String TAG = "CustomTestRunner";
+
+ @Override
+ public void onStart() {
+
+ runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ Context app = CustomTestRunner.this.getTargetContext().getApplicationContext();
+
+ CustomTestRunner.this.disableAnimations(app);
+
+ String name = CustomTestRunner.class.getSimpleName();
+ unlockScreen(app, name);
+ keepSceenAwake(app, name);
+ }
+ });
+
+ super.onStart();
+ }
+
+
+ @Override
+ public void finish(int resultCode, Bundle results) {
+ super.finish(resultCode, results);
+ enableAnimations(getContext());
+ }
+ private void keepSceenAwake(Context app, String name) {
+ PowerManager power = (PowerManager) app.getSystemService(Context.POWER_SERVICE);
+ power.newWakeLock(PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE, name)
+ .acquire();
+ }
+
+ private void unlockScreen(Context app, String name) {
+ KeyguardManager keyguard = (KeyguardManager) app.getSystemService(Context.KEYGUARD_SERVICE);
+ keyguard.newKeyguardLock(name).disableKeyguard();
+ }
+
+ void disableAnimations(Context context) {
+ int permStatus = context.checkCallingOrSelfPermission(Manifest.permission.SET_ANIMATION_SCALE);
+ if (permStatus == PackageManager.PERMISSION_GRANTED) {
+ setSystemAnimationsScale(0.0f);
+ }
+ }
+
+ void enableAnimations(Context context) {
+ int permStatus = context.checkCallingOrSelfPermission(Manifest.permission.SET_ANIMATION_SCALE);
+ if (permStatus == PackageManager.PERMISSION_GRANTED) {
+ setSystemAnimationsScale(1.0f);
+ }
+ }
+
+ private void setSystemAnimationsScale(float animationScale) {
+ try {
+ Class> windowManagerStubClazz = Class.forName("android.view.IWindowManager$Stub");
+ Method asInterface = windowManagerStubClazz.getDeclaredMethod("asInterface", IBinder.class);
+ Class> serviceManagerClazz = Class.forName("android.os.ServiceManager");
+ Method getService = serviceManagerClazz.getDeclaredMethod("getService", String.class);
+ Class> windowManagerClazz = Class.forName("android.view.IWindowManager");
+ Method setAnimationScales = windowManagerClazz.getDeclaredMethod("setAnimationScales", float[].class);
+ Method getAnimationScales = windowManagerClazz.getDeclaredMethod("getAnimationScales");
+
+ IBinder windowManagerBinder = (IBinder) getService.invoke(null, "window");
+ Object windowManagerObj = asInterface.invoke(null, windowManagerBinder);
+ float[] currentScales = (float[]) getAnimationScales.invoke(windowManagerObj);
+ for (int i = 0; i < currentScales.length; i++) {
+ currentScales[i] = animationScale;
+ }
+ setAnimationScales.invoke(windowManagerObj, new Object[]{currentScales});
+ Log.d(TAG, "Changed permissions of animations");
+ } catch (Exception e) {
+ Log.e(TAG, "Could not change animation scale to " + animationScale + " :'(");
+ }
+ }
+}
diff --git a/app/src/androidTest/java/org/bookdash/android/presentation/about/AboutActivityTest.java b/app/src/androidTest/java/org/bookdash/android/presentation/about/AboutFragmentTest.java
similarity index 73%
rename from app/src/androidTest/java/org/bookdash/android/presentation/about/AboutActivityTest.java
rename to app/src/androidTest/java/org/bookdash/android/presentation/about/AboutFragmentTest.java
index d24eff9..c3575a0 100644
--- a/app/src/androidTest/java/org/bookdash/android/presentation/about/AboutActivityTest.java
+++ b/app/src/androidTest/java/org/bookdash/android/presentation/about/AboutFragmentTest.java
@@ -6,38 +6,30 @@
import android.support.test.espresso.intent.Intents;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.support.v4.widget.NestedScrollView;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.Html;
-import android.view.View;
import junit.framework.Assert;
import org.bookdash.android.R;
+import org.bookdash.android.presentation.main.MainActivity;
+import org.bookdash.android.presentation.utils.NavigationUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-
import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.action.ViewActions.scrollTo;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.intent.Intents.intended;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.RootMatchers.isDialog;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static org.hamcrest.Matchers.allOf;
-import static org.hamcrest.Matchers.contains;
-
-
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
/**
* @author rebeccafranks
@@ -45,17 +37,19 @@
*/
@RunWith(AndroidJUnit4.class)
@SmallTest
-public class AboutActivityTest {
+public class AboutFragmentTest {
@Rule
- public ActivityTestRule testRule = new ActivityTestRule<>(AboutActivity.class);
+ public ActivityTestRule testRule = new ActivityTestRule<>(MainActivity.class);
@Before
- public void setUp(){
+ public void setUp() {
Intents.init();
+ NavigationUtils.selectNavDrawItem(testRule.getActivity(), R.id.action_about);
+
}
@After
- public void tearDown(){
+ public void tearDown() {
Intents.release();
}
@@ -76,12 +70,13 @@ public void clickLearnMore_OpenBrowser() throws Throwable {
onView(withText(R.string.learn_more)).perform(scrollTo(), click());
intended(allOf(hasAction(Intent.ACTION_VIEW),
- hasData(Uri.parse("http://bookdash.org"))
+ hasData(Uri.parse("http://bookdash.org"))
)
);
}
+
@Test
- public void testGetScreenName(){
- Assert.assertEquals("About Screen",testRule.getActivity().getScreenName());
+ public void testGetScreenName() {
+ Assert.assertEquals("MainActivity", testRule.getActivity().getScreenName());
}
}
diff --git a/app/src/androidTest/java/org/bookdash/android/presentation/listbooks/OverflowMenuOptionsTest.java b/app/src/androidTest/java/org/bookdash/android/presentation/listbooks/OverflowMenuOptionsTest.java
index 6907aa5..46ef061 100644
--- a/app/src/androidTest/java/org/bookdash/android/presentation/listbooks/OverflowMenuOptionsTest.java
+++ b/app/src/androidTest/java/org/bookdash/android/presentation/listbooks/OverflowMenuOptionsTest.java
@@ -1,20 +1,13 @@
package org.bookdash.android.presentation.listbooks;
-import android.content.Intent;
-import android.net.Uri;
-import android.support.design.widget.NavigationView;
-import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.intent.Intents;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.LargeTest;
-import android.view.MenuItem;
-import org.bookdash.android.BuildConfig;
import org.bookdash.android.R;
-import org.bookdash.android.presentation.about.AboutActivity;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
+import org.bookdash.android.presentation.main.MainActivity;
+import org.bookdash.android.presentation.utils.NavigationUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -22,24 +15,12 @@
import org.junit.runner.RunWith;
import static android.support.test.espresso.Espresso.onView;
-import static android.support.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
import static android.support.test.espresso.matcher.RootMatchers.isDialog;
-import static android.support.test.espresso.matcher.RootMatchers.*;
-import static android.support.test.espresso.matcher.ViewMatchers.isClickable;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.hamcrest.Matchers.*;
-import static org.hamcrest.Matchers.contains;
-
-
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
/**
* @author Rebecca Franks (rebecca.franks@dstvdm.com)
@@ -49,8 +30,8 @@
@LargeTest
public class OverflowMenuOptionsTest {
@Rule
- public ActivityTestRule mActivityTestRule =
- new ActivityTestRule<>(ListBooksActivity.class);
+ public ActivityTestRule mActivityTestRule =
+ new ActivityTestRule<>(MainActivity.class);
@Before
@@ -73,29 +54,17 @@ public void languageItemClick_ShowLanguageChooser() {
@Test
public void aboutMenuClick_ShowAboutBookDashScreen() {
//When
- selectNavDrawItem(R.id.action_about);
+ NavigationUtils.selectNavDrawItem(mActivityTestRule.getActivity(), R.id.action_about);
//Then
- intended(hasComponent(AboutActivity.class.getName()));
+ onView(withText(R.string.title_activity_about)).check(matches(isDisplayed()));
}
- @Test
- public void rateThisAppClick_ShowPlayStoreDetail() {
- //Given
- //When
- selectNavDrawItem(R.id.action_rate_app);
- //Then
- intended(allOf(hasAction(Intent.ACTION_VIEW),
- hasData(Uri.parse("market://details?id=" + org.bookdash.android.BuildConfig.APPLICATION_ID))
- )
- );
- }
-
@Test
public void contributorsClicked_ShowThanksPopover() {
//When
- selectNavDrawItem(R.id.action_thanks);
+ NavigationUtils.selectNavDrawItem(mActivityTestRule.getActivity(), R.id.action_thanks);
//Then
onView(withText("Contributors")).inRoot(isDialog()).check(matches(isDisplayed()));
@@ -104,24 +73,12 @@ public void contributorsClicked_ShowThanksPopover() {
@Test
public void contributorsOkClick_HideThanksPopover() {
//When
- selectNavDrawItem(R.id.action_thanks);
+ NavigationUtils.selectNavDrawItem(mActivityTestRule.getActivity(), R.id.action_thanks);
//Then
onView(withText(android.R.string.ok)).perform(click());
}
- // Due to the NavigationItem not being exposed, we have to do this work around to test NavigationView
- // https://code.google.com/p/android/issues/detail?id=187701
- public void selectNavDrawItem(final int navItemId){
- onView(allOf(withContentDescription(containsString("Navigate up")), isClickable())).perform(click());
- final NavigationView navigation =(NavigationView) mActivityTestRule.getActivity().findViewById(R.id.navigation_view);
- mActivityTestRule.getActivity().runOnUiThread(new Runnable() {
- @Override
- public void run() {
- navigation.getMenu().performIdentifierAction(navItemId, 0);
- navigation.setCheckedItem(navItemId);
- }
- });
- }
+
}
diff --git a/app/src/androidTest/java/org/bookdash/android/presentation/utils/NavigationUtils.java b/app/src/androidTest/java/org/bookdash/android/presentation/utils/NavigationUtils.java
new file mode 100644
index 0000000..81fe5f9
--- /dev/null
+++ b/app/src/androidTest/java/org/bookdash/android/presentation/utils/NavigationUtils.java
@@ -0,0 +1,29 @@
+package org.bookdash.android.presentation.utils;
+
+import android.app.Activity;
+import android.support.design.widget.NavigationView;
+
+import org.bookdash.android.R;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.matcher.ViewMatchers.isClickable;
+import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
+import static org.hamcrest.Matchers.allOf;
+import static org.hamcrest.Matchers.containsString;
+
+
+public class NavigationUtils {
+
+ public static void selectNavDrawItem(Activity activity, final int navItemId){
+ onView(allOf(withContentDescription(containsString("Navigate up")), isClickable())).perform(click());
+ final NavigationView navigation =(NavigationView) activity.findViewById(R.id.navigation_view);
+ activity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ navigation.getMenu().performIdentifierAction(navItemId, 0);
+ navigation.setCheckedItem(navItemId);
+ }
+ });
+ }
+}
diff --git a/app/src/androidTestMock/java/org.bookdash.android/presentation/bookinfo/BookInfoActivityTest.java b/app/src/androidTestMock/java/org.bookdash.android/presentation/bookinfo/BookInfoActivityTest.java
index f8f3420..1cfd805 100644
--- a/app/src/androidTestMock/java/org.bookdash.android/presentation/bookinfo/BookInfoActivityTest.java
+++ b/app/src/androidTestMock/java/org.bookdash.android/presentation/bookinfo/BookInfoActivityTest.java
@@ -8,64 +8,16 @@
import android.test.suitebuilder.annotation.LargeTest;
import org.bookdash.android.domain.pojo.BookDetailParcelable;
-import org.bookdash.android.presentation.listbooks.BookViewHolder;
-import org.bookdash.android.presentation.listbooks.ListBooksActivity;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.espresso.intent.Intents;
-import android.support.test.espresso.matcher.BoundedMatcher;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.Toolbar;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.MenuItem;
-
-import org.bookdash.android.R;
-import org.bookdash.android.presentation.about.AboutActivity;
-import org.bookdash.android.presentation.bookinfo.BookInfoActivity;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.bookdash.android.test.BuildConfig;
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.Espresso.*;
-import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.RootMatchers.isDialog;
-import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withEffectiveVisibility;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.hamcrest.Matchers.*;
-import static org.hamcrest.Matchers.contains;
-
-
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
/**
* @author rebeccafranks
@@ -88,10 +40,11 @@ public void setUp() {
public void tearDown() {
Intents.release();
}
+
public static final String BOOK_OBJ_ID = "f4r2gho2h";
@Test
- public void loadBookInfo_DisplayBookInformation(){
+ public void loadBookInfo_DisplayBookInformation() {
Intent intent = new Intent();
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
BookDetailParcelable bookDetailParcelable = new BookDetailParcelable();
diff --git a/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksActivityTest.java b/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksActivityTest.java
index 03eea6a..cbc2869 100644
--- a/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksActivityTest.java
+++ b/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksActivityTest.java
@@ -1,10 +1,5 @@
package org.bookdash.android.presentation.listbooks;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.support.design.widget.NavigationView;
-import android.support.test.InstrumentationRegistry;
import android.support.test.espresso.ViewInteraction;
import android.support.test.espresso.intent.Intents;
import android.support.test.espresso.matcher.BoundedMatcher;
@@ -12,15 +7,13 @@
import android.support.test.runner.AndroidJUnit4;
import android.support.v7.widget.Toolbar;
import android.test.suitebuilder.annotation.LargeTest;
-import android.view.MenuItem;
import junit.framework.Assert;
import org.bookdash.android.R;
import org.bookdash.android.data.settings.FakeSettingsApiImpl;
-import org.bookdash.android.presentation.about.AboutActivity;
import org.bookdash.android.presentation.bookinfo.BookInfoActivity;
-import org.hamcrest.BaseMatcher;
+import org.bookdash.android.presentation.main.MainActivity;
import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.junit.After;
@@ -28,35 +21,18 @@
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.bookdash.android.test.BuildConfig;
-
-import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.Espresso.*;
+import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
+import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.RootMatchers.isDialog;
-import static android.support.test.espresso.matcher.ViewMatchers.isClickable;
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withContentDescription;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.hamcrest.Matchers.*;
-import static org.hamcrest.Matchers.contains;
-
-
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
+import static org.hamcrest.Matchers.is;
/**
* @author rebeccafranks
@@ -67,8 +43,8 @@
public class ListBooksActivityTest {
@Rule
- public ActivityTestRule activityTestRule =
- new ActivityTestRule<>(ListBooksActivity.class);
+ public ActivityTestRule activityTestRule =
+ new ActivityTestRule<>(MainActivity.class);
@Before
public void setUp() {
@@ -109,8 +85,8 @@ public void openScreen_AppBarTitleIsCorrect() {
@Test
- public void chooseDifferentLanguage_NewBooksLoaded(){
- // selectNavDrawItem(R.id.action_language_choice);
+ public void chooseDifferentLanguage_NewBooksLoaded() {
+ // selectNavDrawItem(R.id.action_language_choice);
onView(withId(R.id.action_language_choice)).perform(click());
//When
@@ -124,12 +100,11 @@ public void chooseDifferentLanguage_NewBooksLoaded(){
}
@Test
- public void testGetScreenName_IsBookListing(){
- Assert.assertEquals("BookListingScreen", activityTestRule.getActivity().getScreenName());
+ public void testGetScreenName_IsBookListing() {
+ Assert.assertEquals("MainActivity", activityTestRule.getActivity().getScreenName());
}
-
private static ViewInteraction matchToolbarTitle(
CharSequence title) {
return onView(isAssignableFrom(Toolbar.class))
diff --git a/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksFailActivityTest.java b/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksFailActivityTest.java
index ef42c54..2a6cc84 100644
--- a/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksFailActivityTest.java
+++ b/app/src/androidTestMock/java/org.bookdash.android/presentation/listbooks/ListBooksFailActivityTest.java
@@ -4,70 +4,22 @@
import android.support.test.espresso.intent.Intents;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
-import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.LargeTest;
import org.bookdash.android.R;
import org.bookdash.android.data.books.FakeBookDetailApiImpl;
-import org.bookdash.android.data.settings.FakeSettingsApiImpl;
+import org.bookdash.android.presentation.main.MainActivity;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
-import java.util.List;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.espresso.ViewInteraction;
-import android.support.test.espresso.intent.Intents;
-import android.support.test.espresso.matcher.BoundedMatcher;
-import android.support.test.rule.ActivityTestRule;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.v7.widget.Toolbar;
-import android.test.suitebuilder.annotation.LargeTest;
-import android.view.MenuItem;
-
-import org.bookdash.android.R;
-import org.bookdash.android.data.settings.FakeSettingsApiImpl;
-import org.bookdash.android.presentation.about.AboutActivity;
-import org.bookdash.android.presentation.bookinfo.BookInfoActivity;
-import org.hamcrest.BaseMatcher;
-import org.hamcrest.Description;
-import org.hamcrest.Matcher;
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.bookdash.android.test.BuildConfig;
-
-
-import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
-import static android.support.test.espresso.Espresso.*;
+import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.RootMatchers.isDialog;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static android.support.test.espresso.action.ViewActions.click;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasAction;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasData;
-import static android.support.test.espresso.matcher.ViewMatchers.withId;
-import static android.support.test.espresso.matcher.ViewMatchers.withText;
-import static org.hamcrest.Matchers.*;
-import static org.hamcrest.Matchers.contains;
-
-
-import static android.support.test.espresso.intent.Intents.intended;
-import static android.support.test.espresso.intent.matcher.IntentMatchers.hasComponent;
/**
* @author rebeccafranks
@@ -77,22 +29,22 @@
@LargeTest
public class ListBooksFailActivityTest {
@Rule
- public ActivityTestRule activityActivityTestRule = new ActivityTestRule<>(ListBooksActivity.class, true, false);
+ public ActivityTestRule activityActivityTestRule = new ActivityTestRule<>(MainActivity.class, true, false);
@Before
- public void setUp(){
+ public void setUp() {
Intents.init();
}
@After
- public void tearDown(){
+ public void tearDown() {
Intents.release();
}
@Test
- public void loadLanguages_LoadError_ShowSnackBarMessage(){
+ public void loadLanguages_LoadError_ShowSnackBarMessage() {
FakeBookDetailApiImpl.setShouldFailService(true);
activityActivityTestRule.launchActivity(null);
@@ -104,7 +56,7 @@ public void loadLanguages_LoadError_ShowSnackBarMessage(){
}
@Test
- public void loadBooks_LoadError_ShowRetryButton(){
+ public void loadBooks_LoadError_ShowRetryButton() {
FakeBookDetailApiImpl.setShouldFailService(true);
activityActivityTestRule.launchActivity(null);
@@ -115,7 +67,7 @@ public void loadBooks_LoadError_ShowRetryButton(){
}
@Test
- public void clickRetryButton_ReloadsBooksDisplayed(){
+ public void clickRetryButton_ReloadsBooksDisplayed() {
//Given
FakeBookDetailApiImpl.setShouldFailService(true);
activityActivityTestRule.launchActivity(null);
diff --git a/app/src/androidTestMock/java/org.bookdash.android/presentation/splash/SplashScreenTest.java b/app/src/androidTestMock/java/org.bookdash.android/presentation/splash/SplashScreenTest.java
index 4fbf970..84c52e8 100644
--- a/app/src/androidTestMock/java/org.bookdash.android/presentation/splash/SplashScreenTest.java
+++ b/app/src/androidTestMock/java/org.bookdash.android/presentation/splash/SplashScreenTest.java
@@ -10,7 +10,7 @@
import android.test.suitebuilder.annotation.LargeTest;
import org.bookdash.android.data.settings.FakeSettingsApiImpl;
-import org.bookdash.android.presentation.listbooks.ListBooksActivity;
+import org.bookdash.android.presentation.main.MainActivity;
import org.bookdash.android.presentation.splash.util.ElapsedTimeIdlingResource;
import org.junit.After;
import org.junit.Before;
@@ -72,7 +72,7 @@ public void viewSplashScreenSecondTime_NavigateToListBooksAfter1000ms() throws I
Espresso.registerIdlingResources(idlingResource);
- intended(hasComponent(ListBooksActivity.class.getName()));
+ intended(hasComponent(MainActivity.class.getName()));
Espresso.unregisterIdlingResources(idlingResource);
@@ -90,7 +90,7 @@ public void viewSplashScreenFinish_StartListBooks(){
intending(hasComponent(MaterialTutorialActivity.class.getName())).respondWith(result);
- intended(hasComponent(ListBooksActivity.class.getName()));
+ intended(hasComponent(MainActivity.class.getName()));
Espresso.unregisterIdlingResources(idlingResource);
}
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index b8df01d..6b00261 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,38 +1,39 @@
-
+
-
-
-
+
+
+
-
-
-
-
+
+
+
+
+
-
+
+
+
-
-
+ android:value=".presentation.main.MainActivity"/>
+
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+ android:pathPrefix="/books"
+ android:scheme="http"/>
-
-
+
-
-
-
+
+
-
-
+
+
-
+
-
-
+
+
-
+
-
+
-
-
-
+
+
+
-
+
+ android:value="@integer/google_play_services_version"/>
+ android:value="b2579d751611dc3b58788bad80a51ad37e140ecb"/>
diff --git a/app/src/main/java/org/bookdash/android/data/books/BookDetailApi.java b/app/src/main/java/org/bookdash/android/data/books/BookDetailApi.java
index 2ad0f8c..e8d94b0 100644
--- a/app/src/main/java/org/bookdash/android/data/books/BookDetailApi.java
+++ b/app/src/main/java/org/bookdash/android/data/books/BookDetailApi.java
@@ -16,12 +16,15 @@ public interface BookDetailApi {
void getBooksForLanguages(String language, BookServiceCallback> bookServiceCallback);
+ void getDownloadedBooks(BookServiceCallback> bookServiceCallback);
+
interface BookServiceCallback {
void onLoaded(T result);
void onError(Exception error);
}
- interface BookServiceProgressCallback{
+
+ interface BookServiceProgressCallback {
void onProgressChanged(int progress);
}
@@ -34,4 +37,5 @@ interface BookServiceProgressCallback{
void downloadBook(BookDetail bookDetail, BookServiceCallback downloadBookCallback, BookServiceProgressCallback bookServiceProgressCallback);
+ void deleteBook(BookDetail bookDetail, BookServiceCallback deleteBook);
}
diff --git a/app/src/main/java/org/bookdash/android/data/books/BookDetailApiImpl.java b/app/src/main/java/org/bookdash/android/data/books/BookDetailApiImpl.java
index a7ee645..1d13b57 100644
--- a/app/src/main/java/org/bookdash/android/data/books/BookDetailApiImpl.java
+++ b/app/src/main/java/org/bookdash/android/data/books/BookDetailApiImpl.java
@@ -1,6 +1,7 @@
package org.bookdash.android.data.books;
import android.support.annotation.NonNull;
+import android.support.annotation.WorkerThread;
import android.util.Log;
import com.google.gson.Gson;
@@ -12,19 +13,20 @@
import com.parse.ProgressCallback;
import org.bookdash.android.BookDashApplication;
+import org.bookdash.android.data.utils.FileManager;
+import org.bookdash.android.data.utils.ZipManager;
import org.bookdash.android.domain.pojo.Book;
import org.bookdash.android.domain.pojo.BookContributor;
import org.bookdash.android.domain.pojo.BookDetail;
import org.bookdash.android.domain.pojo.Language;
import org.bookdash.android.domain.pojo.gson.BookPages;
-import org.bookdash.android.data.utils.FileManager;
-import org.bookdash.android.data.utils.ZipManager;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
@@ -65,6 +67,38 @@ public void done(List list, ParseException e) {
});
}
+ private List filterOnlyDownloadedBooks(List bookDetails) {
+ List bookDetailsDownloaded = new ArrayList<>();
+
+ for (BookDetail b : bookDetails) {
+ if (b.isDownloadedAlready() || b.isDownloading()) {
+ bookDetailsDownloaded.add(b);
+ }
+ }
+ return bookDetailsDownloaded;
+ }
+
+ @Override
+ public void getDownloadedBooks(final BookServiceCallback> bookServiceCallback) {
+
+ ParseQuery queryBookDetail = ParseQuery.getQuery(BookDetail.class);
+ queryBookDetail.setCachePolicy(ParseQuery.CachePolicy.NETWORK_ELSE_CACHE);
+ queryBookDetail.include(BookDetail.BOOK_LANGUAGE_COL);
+ queryBookDetail.include(BookDetail.BOOK_ID_COL);
+ queryBookDetail.whereEqualTo(BookDetail.BOOK_ENABLED_COL, true);
+ queryBookDetail.addDescendingOrder(BookDetail.CREATED_AT_COL);
+ queryBookDetail.findInBackground(new FindCallback() {
+ @Override
+ public void done(List list, ParseException e) {
+ if (e != null) {
+ bookServiceCallback.onError(e);
+ return;
+ }
+ bookServiceCallback.onLoaded(filterOnlyDownloadedBooks(list));
+ }
+ });
+ }
+
@Override
public void getBookDetail(String bookDetailId, final BookServiceCallback bookServiceCallback) {
ParseQuery queryBookDetail = ParseQuery.getQuery(BookDetail.class);
@@ -127,9 +161,9 @@ public void done(List list, ParseException e) {
@Override
public void downloadBook(final BookDetail bookInfo, @NonNull final BookServiceCallback downloadBookCallback, @NonNull final BookServiceProgressCallback progressCallback) {
- if (bookInfo.isDownloadedAlready()){
+ if (bookInfo.isDownloadedAlready()) {
progressCallback.onProgressChanged(100);
- downloadBookCallback.onLoaded(getBookPages(bookInfo.getFolderLocation(BookDashApplication.FILES_DIR) + File.separator + BookDetail.BOOK_INFO_FILE_NAME ));
+ downloadBookCallback.onLoaded(getBookPages(bookInfo.getFolderLocation() + File.separator + BookDetail.BOOK_INFO_FILE_NAME));
return;
}
bookInfo.getBookFile().getDataInBackground(new GetDataCallback() {
@@ -161,6 +195,29 @@ public void done(Integer progressInt) {
});
}
+ @Override
+ public void deleteBook(final BookDetail bookDetail, final BookServiceCallback deleteBook) {
+ Task.call(new Callable() {
+ @Override
+ public Void call() throws Exception {
+ try {
+ deleteLocalBook(bookDetail);
+ deleteBook.onLoaded(true);
+ } catch (Exception e) {
+ deleteBook.onError(e);
+ }
+ return null;
+
+ }
+ }, DISK_EXECUTOR);
+ }
+
+ @WorkerThread
+ private void deleteLocalBook(BookDetail bookDetail) {
+ FileManager.deleteFolder(bookDetail.getFolderLocation());
+ FileManager.deleteFolder(BookDashApplication.FILES_DIR + "/" + bookDetail.getObjectId());
+ }
+
private void getBookPages(final BookDetail bookInfo, final byte[] bytes, final BookServiceCallback bookServiceCallback) {
Task.call(new Callable() {
@Override
@@ -177,19 +234,21 @@ public BookPages call() throws Exception {
}
+ @WorkerThread
private BookPages saveBook(byte[] bytes, BookDetail bookDetail) {
String targetLocation = BookDashApplication.FILES_DIR + File.separator + bookDetail.getObjectId();
String fileLocation = BookDashApplication.FILES_DIR + File.separator + bookDetail.getBookFile().getName();
File f = new File("", targetLocation);
- if (!f.exists()) {
+ if (!f.exists() || f.list().length == 0) {
FileManager.saveFile(BookDashApplication.FILES_DIR, bytes, File.separator + bookDetail.getBookFile().getName());
ZipManager zipManager = new ZipManager();
zipManager.unzip(fileLocation, targetLocation);
+
FileManager.deleteFile(BookDashApplication.FILES_DIR, File.separator + bookDetail.getBookFile().getName());
}
- return getBookPages(bookDetail.getFolderLocation(BookDashApplication.FILES_DIR) + File.separator + BookDetail.BOOK_INFO_FILE_NAME);
+ return getBookPages(bookDetail.getFolderLocation() + File.separator + BookDetail.BOOK_INFO_FILE_NAME);
}
diff --git a/app/src/main/java/org/bookdash/android/data/books/BookDetailRepository.java b/app/src/main/java/org/bookdash/android/data/books/BookDetailRepository.java
index 3717b1a..843900d 100644
--- a/app/src/main/java/org/bookdash/android/data/books/BookDetailRepository.java
+++ b/app/src/main/java/org/bookdash/android/data/books/BookDetailRepository.java
@@ -16,7 +16,10 @@
*/
public interface BookDetailRepository {
- void getBooksForLanguage(String language, boolean downloadedOnly, @NonNull GetBooksForLanguageCallback booksForLanguageCallback);
+
+ void getBooksForLanguage(@NonNull String language, @NonNull GetBooksForLanguageCallback booksForLanguageCallback);
+
+ void getDownloadedBooks(GetBooksForLanguageCallback getBooksForLanguageCallback);
interface GetBooksForLanguageCallback {
void onBooksLoaded(List books);
@@ -37,7 +40,6 @@ interface GetContributorsCallback {
}
-
interface GetLanguagesCallback {
void onLanguagesLoaded(List languages);
@@ -46,7 +48,9 @@ interface GetLanguagesCallback {
interface GetBookPagesCallback {
void onBookPagesLoaded(BookPages bookPages);
+
void onBookPagesLoadError(Exception e);
+
void onBookPagesDownloadProgressUpdate(int progress);
}
@@ -57,4 +61,13 @@ interface GetBookPagesCallback {
void getLanguages(@NonNull GetLanguagesCallback languagesCallback);
void downloadBook(BookDetail bookDetail, @NonNull GetBookPagesCallback bookPagesCallback);
+
+ void deleteBook(BookDetail bookDetail, @NonNull DeleteBookCallBack deleteBookCallBack);
+
+ interface DeleteBookCallBack {
+ void onBookDeleted(BookDetail bookDetail);
+
+ void onBookDeleteFailed(Exception e);
+
+ }
}
diff --git a/app/src/main/java/org/bookdash/android/data/books/BookDetailRepositoryImpl.java b/app/src/main/java/org/bookdash/android/data/books/BookDetailRepositoryImpl.java
index 6bd32d6..591d837 100644
--- a/app/src/main/java/org/bookdash/android/data/books/BookDetailRepositoryImpl.java
+++ b/app/src/main/java/org/bookdash/android/data/books/BookDetailRepositoryImpl.java
@@ -8,7 +8,6 @@
import org.bookdash.android.domain.pojo.Language;
import org.bookdash.android.domain.pojo.gson.BookPages;
-import java.util.ArrayList;
import java.util.List;
/**
@@ -26,16 +25,12 @@ public BookDetailRepositoryImpl(@NonNull BookDetailApi bookDetailApi) {
}
@Override
- public void getBooksForLanguage(@NonNull String language, final boolean downloadedOnly, @NonNull final GetBooksForLanguageCallback booksForLanguageCallback) {
+ public void getBooksForLanguage(@NonNull String language, @NonNull final GetBooksForLanguageCallback booksForLanguageCallback) {
bookDetailApi.getBooksForLanguages(language, new BookDetailApi.BookServiceCallback>() {
@Override
public void onLoaded(List result) {
- if (downloadedOnly) {
- booksForLanguageCallback.onBooksLoaded(filterOnlyDownloadedBooks(result));
- } else {
- booksForLanguageCallback.onBooksLoaded(result);
- }
+ booksForLanguageCallback.onBooksLoaded(result);
}
@Override
@@ -45,16 +40,24 @@ public void onError(Exception error) {
});
}
- private List filterOnlyDownloadedBooks(List bookDetails){
- List bookDetailsDownloaded = new ArrayList<>();
+ @Override
+ public void getDownloadedBooks(final GetBooksForLanguageCallback getBooksForLanguageCallback) {
+ bookDetailApi.getDownloadedBooks(new BookDetailApi.BookServiceCallback>() {
- for (BookDetail b: bookDetails){
- if (b.isDownloadedAlready() || b.isDownloading()){
- bookDetailsDownloaded.add(b);
+ @Override
+ public void onLoaded(List result) {
+ getBooksForLanguageCallback.onBooksLoaded(result);
}
- }
- return bookDetailsDownloaded;
+
+ @Override
+ public void onError(Exception error) {
+ getBooksForLanguageCallback.onBooksLoadError(error);
+ }
+ });
+
}
+
+
@Override
public void getBookDetail(String bookDetailId, @NonNull final GetBookDetailCallback bookDetailCallback) {
bookDetailApi.getBookDetail(bookDetailId, new BookDetailApi.BookServiceCallback() {
@@ -122,5 +125,20 @@ public void onProgressChanged(int progress) {
});
}
+ @Override
+ public void deleteBook(final BookDetail bookDetail, @NonNull final DeleteBookCallBack deleteBookCallBack) {
+ bookDetailApi.deleteBook(bookDetail, new BookDetailApi.BookServiceCallback() {
+ @Override
+ public void onLoaded(Boolean result) {
+ deleteBookCallBack.onBookDeleted(bookDetail);
+ }
+
+ @Override
+ public void onError(Exception error) {
+ deleteBookCallBack.onBookDeleteFailed(error);
+ }
+ });
+ }
+
}
diff --git a/app/src/main/java/org/bookdash/android/data/utils/FileManager.java b/app/src/main/java/org/bookdash/android/data/utils/FileManager.java
index 4ed8409..d9e8fd0 100644
--- a/app/src/main/java/org/bookdash/android/data/utils/FileManager.java
+++ b/app/src/main/java/org/bookdash/android/data/utils/FileManager.java
@@ -20,7 +20,7 @@ public static void saveFile(String filesDir, byte[] bytes, String fileName) {
FileOutputStream outputStream = null;
try {
- if (file.exists()){
+ if (file.exists()) {
Log.d(TAG, "File exists- not saving again");
return;
}
@@ -40,8 +40,32 @@ public static void saveFile(String filesDir, byte[] bytes, String fileName) {
}
}
- public static boolean deleteFile(String filesDir, String fileName){
+
+ public static boolean deleteFile(String filesDir, String fileName) {
File file = new File(filesDir, fileName);
return file.delete();
}
+
+ public static void deleteFolder(String folderLocation) {
+ deleteRecursive(new File(folderLocation));
+ }
+
+ private static void deleteRecursive(File fileOrDirectory) {
+ if (fileOrDirectory.isDirectory()) {
+ File[] list = fileOrDirectory.listFiles();
+ if (list != null) {
+ for (int i = 0; i < list.length; i++) {
+ File tmpF = list[i];
+ if (tmpF.isDirectory()) {
+ deleteRecursive(tmpF);
+ }
+ tmpF.delete();
+ }
+ }
+ if (!fileOrDirectory.delete()) {
+ Log.e(TAG, "can't delete folder : " + fileOrDirectory);
+ }
+ }
+ }
+
}
diff --git a/app/src/main/java/org/bookdash/android/domain/pojo/BookDetail.java b/app/src/main/java/org/bookdash/android/domain/pojo/BookDetail.java
index aadedc9..d8dfde3 100644
--- a/app/src/main/java/org/bookdash/android/domain/pojo/BookDetail.java
+++ b/app/src/main/java/org/bookdash/android/domain/pojo/BookDetail.java
@@ -40,7 +40,7 @@ public BookDetail(String title, String bookCoverUrl, String objectId, Language l
put(BOOK_COVER_PAGE_URL_COL, bookCoverUrl);
put(BOOK_LANGUAGE_COL, languageId);
setObjectId(objectId);
- // put(OBJECT_ID, objectId);
+ // put(OBJECT_ID, objectId);
//put();
}
@@ -69,23 +69,30 @@ public String getAboutBook() {
}
- public String getFolderLocation(String filesDir) {
- return getFolderLocation(new File(filesDir, getObjectId() + File.separator));
+ public String getFolderLocation() {
+ return getFolderLocation(new File(BookDashApplication.FILES_DIR, getObjectId() + File.separator));
}
private String getFolderLocation(File file) {
- if (file.isDirectory() && (file.canRead())) {
+ if (file != null && file.isDirectory() && (file.canRead())) {
File[] files = file.listFiles();
+ if (files == null || files.length == 0 || files[0] == null) {
+ return null;
+ }
return files[0].getAbsoluteFile().toString();
}
return null;
}
public boolean isDownloadedAlready() {
- String targetLocation = BookDashApplication.FILES_DIR + File.separator + getObjectId();
- File f = new File("", targetLocation);
+ String folderLocation = getFolderLocation();
+ if (folderLocation == null || folderLocation.isEmpty()) {
+ return false;
+ }
+ File f = new File("", folderLocation);
return f.exists();
}
+
public boolean isDownloading() {
return isDownloading;
}
diff --git a/app/src/main/java/org/bookdash/android/presentation/about/AboutActivity.java b/app/src/main/java/org/bookdash/android/presentation/about/AboutActivity.java
deleted file mode 100644
index 810ca4f..0000000
--- a/app/src/main/java/org/bookdash/android/presentation/about/AboutActivity.java
+++ /dev/null
@@ -1,69 +0,0 @@
-package org.bookdash.android.presentation.about;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.support.v7.app.ActionBar;
-import android.support.v7.widget.Toolbar;
-import android.text.Html;
-import android.text.util.Linkify;
-import android.view.View;
-import android.widget.Button;
-import android.widget.TextView;
-
-import org.bookdash.android.BookDashApplication;
-import org.bookdash.android.R;
-import org.bookdash.android.presentation.activity.BaseAppCompatActivity;
-
-public class AboutActivity extends BaseAppCompatActivity implements AboutContract.View {
-
- private AboutPresenter aboutPresenter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_about);
- aboutPresenter = new AboutPresenter(this);
-
- Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
- setSupportActionBar(toolbar);
- ActionBar actionBar = getSupportActionBar();
-
- if (actionBar != null) {
- actionBar.setDisplayHomeAsUpEnabled(true);
- actionBar.setTitle(R.string.about_heading);
- }
-
- TextView textViewWhyBookDash = (TextView) findViewById(R.id.text_why_bookdash);
- textViewWhyBookDash.setText(Html.fromHtml(getString(R.string.why_bookdash)));
- Linkify.addLinks(textViewWhyBookDash, Linkify.ALL);
-
- TextView textViewHeading = (TextView) findViewById(R.id.text_view_about);
- textViewHeading.setText(Html.fromHtml(getString(R.string.heading_about)));
- Linkify.addLinks(textViewHeading, Linkify.ALL);
-
- Button learnMoreBookDash = (Button) findViewById(R.id.button_learn_more);
- learnMoreBookDash.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- aboutPresenter.clickLearnMore();
- }
- });
-
-
- textViewHeading.findFocus();
- }
-
- @Override
- protected String getScreenName() {
- return "About Screen";
- }
-
-
- @Override
- public void showLearnMorePage(String url) {
- Intent intent = new Intent(Intent.ACTION_VIEW);
- intent.setData(Uri.parse(url));
- startActivity(intent);
- }
-}
diff --git a/app/src/main/java/org/bookdash/android/presentation/about/AboutFragment.java b/app/src/main/java/org/bookdash/android/presentation/about/AboutFragment.java
new file mode 100644
index 0000000..00ac6eb
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/about/AboutFragment.java
@@ -0,0 +1,101 @@
+package org.bookdash.android.presentation.about;
+
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.text.Html;
+import android.text.util.Linkify;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+
+import org.bookdash.android.R;
+import org.bookdash.android.presentation.main.NavDrawerInterface;
+
+public class AboutFragment extends Fragment implements AboutContract.View {
+
+ private AboutPresenter aboutPresenter;
+ private NavDrawerInterface navDrawerInterface;
+
+ public static AboutFragment newInstance() {
+
+ Bundle args = new Bundle();
+
+ AboutFragment fragment = new AboutFragment();
+ fragment.setArguments(args);
+ return fragment;
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ super.onCreateView(inflater, container, savedInstanceState);
+ return inflater.inflate(R.layout.activity_about, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ aboutPresenter = new AboutPresenter(this);
+
+ Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar);
+ navDrawerInterface.setToolbar(toolbar);
+ ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp);
+ actionBar.setTitle(R.string.about_heading);
+ }
+
+ TextView textViewWhyBookDash = (TextView) view.findViewById(R.id.text_why_bookdash);
+ textViewWhyBookDash.setText(Html.fromHtml(getString(R.string.why_bookdash)));
+ Linkify.addLinks(textViewWhyBookDash, Linkify.ALL);
+
+ TextView textViewHeading = (TextView) view.findViewById(R.id.text_view_about);
+ textViewHeading.setText(Html.fromHtml(getString(R.string.heading_about)));
+ Linkify.addLinks(textViewHeading, Linkify.ALL);
+
+ Button learnMoreBookDash = (Button) view.findViewById(R.id.button_learn_more);
+ learnMoreBookDash.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ aboutPresenter.clickLearnMore();
+ }
+ });
+
+
+ textViewHeading.findFocus();
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof NavDrawerInterface) {
+ navDrawerInterface = (NavDrawerInterface) context;
+
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ navDrawerInterface = null;
+ }
+
+
+ @Override
+ public void showLearnMorePage(String url) {
+ Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(url));
+ startActivity(intent);
+ }
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoActivity.java b/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoActivity.java
index 4c1da09..b3f4e32 100644
--- a/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoActivity.java
+++ b/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoActivity.java
@@ -44,6 +44,7 @@
import com.parse.ParseException;
import com.parse.ParseFile;
+import org.bookdash.android.BR;
import org.bookdash.android.Injection;
import org.bookdash.android.R;
import org.bookdash.android.domain.pojo.BookContributor;
@@ -52,7 +53,6 @@
import org.bookdash.android.domain.pojo.gson.BookPages;
import org.bookdash.android.presentation.activity.BaseAppCompatActivity;
import org.bookdash.android.presentation.readbook.BookDetailActivity;
-import org.bookdash.android.BR;
import java.util.List;
@@ -160,7 +160,7 @@ public void onClick(View v) {
showSnackBarMessage(R.string.book_not_available);
return;
}
- if (!bookInfo.isDownloadedAlready()){
+ if (!bookInfo.isDownloadedAlready()) {
floatingActionButton.resetIcon();
floatingActionButton.showProgress(true);
floatingActionButton.setProgress(0, true);
@@ -207,6 +207,9 @@ public boolean onOptionsItemSelected(MenuItem item) {
if (id == R.id.action_share_book) {
actionsListener.shareBookClicked(bookInfo);
return true;
+ } else if (id == android.R.id.home) {
+ onBackPressed();
+ return true;
}
return super.onOptionsItemSelected(item);
@@ -231,7 +234,7 @@ protected void onNewIntent(Intent intent) {
Log.d(TAG, "onNewIntent() called: action" + action);
if (Intent.ACTION_VIEW.equals(action) && data != null) {
- Uri uri = Uri.parse(data);
+ Uri uri = Uri.parse(data);
String bookId = uri.getLastPathSegment();
String invitationId = uri.getQueryParameter("invitation_id");
Log.d(TAG, "Action View: book id:" + bookId + ". Full URL:" + uri.toString() + ". InvitationId:" + invitationId);
@@ -300,10 +303,12 @@ public void showSnackBarMessage(int message) {
Snackbar.make(scrollView, message, Snackbar.LENGTH_LONG).show();
}
- private int progress= 0;
+
+ private int progress = 0;
+
@Override
public void showDownloadProgress(final int downloadProgress) {
- if (progress == downloadProgress){
+ if (progress == downloadProgress) {
return;
}
progress = downloadProgress;
@@ -339,7 +344,7 @@ public void setToolbarTitle(String title) {
@Override
public void setBookInfoBinding(BookDetail bookInfo) {
- if (client!=null) {
+ if (client != null) {
client.connect();
}
@@ -352,7 +357,7 @@ public void setBookInfoBinding(BookDetail bookInfo) {
bookInfo.getWebUrl() == null ? null : Uri.parse(bookInfo.getWebUrl()),
Uri.parse("android-app://org.bookdash.android/http/bookdash.org/books/" + bookInfo.getObjectId())
);
- if (viewAction != null && client!=null) {
+ if (viewAction != null && client != null) {
AppIndex.AppIndexApi.start(client, viewAction);
}
}
@@ -401,7 +406,7 @@ public void setStatusBarColor(int color) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
- window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
+ // window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
window.setStatusBarColor(color);
}
}
diff --git a/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoPresenter.java b/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoPresenter.java
index 1c94461..83edd79 100644
--- a/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoPresenter.java
+++ b/app/src/main/java/org/bookdash/android/presentation/bookinfo/BookInfoPresenter.java
@@ -102,7 +102,7 @@ public void onBookPagesLoaded(BookPages bookPages) {
return;
}
bookInfo.setIsDownloading(false);
- booksView.openBook(bookInfo, bookPages, bookInfo.getFolderLocation(BookDashApplication.FILES_DIR));
+ booksView.openBook(bookInfo, bookPages, bookInfo.getFolderLocation());
}
@Override
diff --git a/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsAdapter.java b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsAdapter.java
new file mode 100644
index 0000000..3354570
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsAdapter.java
@@ -0,0 +1,62 @@
+package org.bookdash.android.presentation.downloads;
+
+import android.content.Context;
+import android.support.v7.widget.RecyclerView;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.bumptech.glide.Glide;
+
+import org.bookdash.android.R;
+import org.bookdash.android.domain.pojo.BookDetail;
+
+import java.util.List;
+
+public class DownloadsAdapter extends RecyclerView.Adapter {
+
+ private final View.OnClickListener deleteClickListener;
+ private final View.OnClickListener bookClickListener;
+ private List bookList;
+ private Context context;
+
+ public DownloadsAdapter(List bookList, Context context, View.OnClickListener deleteClickListener, View.OnClickListener bookClickListener) {
+ this.bookList = bookList;
+ this.context = context;
+ this.deleteClickListener = deleteClickListener;
+ this.bookClickListener = bookClickListener;
+ }
+
+ @Override
+ public DownloadsViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+ View v = LayoutInflater.from(parent.getContext())
+ .inflate(R.layout.list_item_download, parent, false);
+
+ return new DownloadsViewHolder(v);
+ }
+
+ @Override
+ public void onBindViewHolder(DownloadsViewHolder holder, int position) {
+ BookDetail book = bookList.get(position);
+ holder.downloadTitleTextView.setText(book.getBookTitle());
+ Glide.with(context).load(book.getBookCoverUrl()).into(holder.downloadImageTextView);
+ holder.downloadProgressTextView.setText(book.getLanguage().getLanguageName());
+ holder.downloadActionButtonView.setOnClickListener(deleteClickListener);
+ holder.book = book;
+ holder.downloadActionButtonView.setTag(holder);
+ holder.downloadRelativeLayout.setOnClickListener(bookClickListener);
+ holder.downloadRelativeLayout.setTag(holder);
+ }
+
+ @Override
+ public int getItemCount() {
+ if (bookList == null) {
+ return 0;
+ }
+ return bookList.size();
+ }
+
+ public void setBooks(List books) {
+ this.bookList = books;
+ }
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsContract.java b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsContract.java
new file mode 100644
index 0000000..54b563d
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsContract.java
@@ -0,0 +1,31 @@
+package org.bookdash.android.presentation.downloads;
+
+
+import org.bookdash.android.domain.pojo.BookDetail;
+
+import java.util.List;
+
+public interface DownloadsContract {
+
+ interface View {
+
+ void showDownloadedBooks(List books);
+
+ void showLoading(boolean show);
+
+ void showErrorScreen(boolean show, String errorMessage, boolean showRetryButton);
+
+ void showSnackBarError(int message);
+
+ void showSnackBarError(String message);
+
+ void showNoBooksDownloadedMessage();
+ }
+
+ interface UserActions {
+ void loadListDownloads();
+
+ void deleteDownload(BookDetail bookDetail);
+ }
+
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsFragment.java b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsFragment.java
new file mode 100644
index 0000000..86868d9
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsFragment.java
@@ -0,0 +1,233 @@
+package org.bookdash.android.presentation.downloads;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.LinearLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+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.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.bookdash.android.Injection;
+import org.bookdash.android.R;
+import org.bookdash.android.domain.pojo.BookDetail;
+import org.bookdash.android.presentation.bookinfo.BookInfoActivity;
+import org.bookdash.android.presentation.main.NavDrawerInterface;
+
+import java.util.List;
+
+import fr.castorflex.android.circularprogressbar.CircularProgressBar;
+
+
+public class DownloadsFragment extends Fragment implements DownloadsContract.View {
+
+ private RecyclerView listDownloadsRecyclerView;
+ private DownloadsContract.UserActions downloadsPresenter;
+ private DownloadsAdapter downloadsAdapter;
+ private LinearLayout linearLayoutErrorScreen;
+ private Button buttonRetry;
+ private TextView textViewErrorMessage;
+ private CircularProgressBar circularProgressBar;
+ private NavDrawerInterface navDrawerInterface;
+ private Toolbar toolbar;
+
+
+ public static DownloadsFragment newInstance() {
+ return new DownloadsFragment();
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_downloads, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ listDownloadsRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_list_downloads);
+ downloadsPresenter = new DownloadsPresenter(Injection.provideBookRepo(), this);
+ downloadsAdapter = new DownloadsAdapter(null, getActivity(), new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ DownloadsViewHolder downloadsViewHolder = (DownloadsViewHolder) v.getTag();
+ showDeleteDialog(downloadsViewHolder.book);
+
+ }
+ }, new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ DownloadsViewHolder downloadsViewHolder = (DownloadsViewHolder) v.getTag();
+ showBookDetails(downloadsViewHolder.book);
+ }
+ });
+ listDownloadsRecyclerView.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.VERTICAL, false));
+ listDownloadsRecyclerView.setAdapter(downloadsAdapter);
+
+ linearLayoutErrorScreen = (LinearLayout) view.findViewById(R.id.linear_layout_error);
+ buttonRetry = (Button) view.findViewById(R.id.button_retry);
+ textViewErrorMessage = (TextView) view.findViewById(R.id.text_view_error_screen);
+ circularProgressBar = (CircularProgressBar) view.findViewById(R.id.fragment_loading_downloads);
+ toolbar = (Toolbar) view.findViewById(R.id.toolbar);
+ if (navDrawerInterface != null) {
+ navDrawerInterface.setToolbar(toolbar);
+
+ }
+
+ final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+
+ if (actionBar != null) {
+ actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setTitle(getString(R.string.fragment_title_downloads));
+ }
+ downloadsPresenter.loadListDownloads();
+
+ setHasOptionsMenu(false);
+ }
+
+ private void showBookDetails(BookDetail bookDetail) {
+ Intent intent = new Intent(getActivity(), BookInfoActivity.class);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(BookInfoActivity.BOOK_PARCEL, bookDetail.toBookParcelable());
+ startActivity(intent);
+ }
+
+ private void showDeleteDialog(final BookDetail bookToDelete) {
+ AlertDialog.Builder builder =
+ new AlertDialog.Builder(getActivity(), R.style.AppCompatAlertDialogStyle);
+ builder.setTitle(getString(R.string.delete_book_confirmation));
+ builder.setMessage(getString(R.string.downloads_are_you_sure, bookToDelete.getBookTitle()));
+ builder.setPositiveButton(getString(R.string.delete_ok), new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ downloadsPresenter.deleteDownload(bookToDelete);
+ }
+ });
+ builder.setNegativeButton(getString(R.string.delete_cancel), null);
+ builder.show();
+ }
+
+ @Override
+ public void showDownloadedBooks(List books) {
+ downloadsAdapter.setBooks(books);
+ downloadsAdapter.notifyDataSetChanged();
+ listDownloadsRecyclerView.setVisibility(View.VISIBLE);
+ }
+
+
+ @Override
+ public void showErrorScreen(boolean show, String errorMessage, boolean showRetryButton) {
+ if (show) {
+ linearLayoutErrorScreen.setVisibility(View.VISIBLE);
+ } else {
+ linearLayoutErrorScreen.setVisibility(View.GONE);
+ }
+ buttonRetry.setVisibility(showRetryButton ? View.VISIBLE : View.GONE);
+ textViewErrorMessage.setText(errorMessage);
+
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+
+ }
+
+ @Override
+ public void showLoading(final boolean visible) {
+ runUiThread(new Runnable() {
+ @Override
+ public void run() {
+
+ circularProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE);
+ listDownloadsRecyclerView.setVisibility(visible ? View.GONE : View.VISIBLE);
+
+ }
+ });
+ }
+
+ @Override
+ public void showSnackBarError(final int message) {
+ runUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Snackbar.make(listDownloadsRecyclerView, message, Snackbar.LENGTH_LONG).show();
+
+ }
+ });
+ }
+
+ private void runUiThread(Runnable runnable) {
+ Activity activity = getActivity();
+ if (activity == null) {
+ return;
+ }
+ activity.runOnUiThread(runnable);
+ }
+
+ @Override
+ public void showSnackBarError(final String message) {
+ runUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Snackbar.make(listDownloadsRecyclerView, message, Snackbar.LENGTH_LONG).show();
+
+ }
+ });
+
+ }
+
+ @Override
+ public void showNoBooksDownloadedMessage() {
+ showErrorScreen(true, getString(R.string.no_books_downloaded), false);
+ listDownloadsRecyclerView.setVisibility(View.GONE);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof NavDrawerInterface) {
+ navDrawerInterface = (NavDrawerInterface) context;
+
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ navDrawerInterface = null;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+
+ case android.R.id.home:
+ if (navDrawerInterface != null) {
+ navDrawerInterface.openNavDrawer();
+ }
+ return true;
+
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsPresenter.java b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsPresenter.java
new file mode 100644
index 0000000..43ac73e
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsPresenter.java
@@ -0,0 +1,55 @@
+package org.bookdash.android.presentation.downloads;
+
+import org.bookdash.android.data.books.BookDetailRepository;
+import org.bookdash.android.domain.pojo.BookDetail;
+
+import java.util.List;
+
+public class DownloadsPresenter implements DownloadsContract.UserActions {
+ private static final String TAG = "DownloadsPresenter";
+ private final BookDetailRepository bookRepository;
+ private final DownloadsContract.View view;
+
+ public DownloadsPresenter(BookDetailRepository bookRepository, DownloadsContract.View downloadsView) {
+ this.bookRepository = bookRepository;
+ this.view = downloadsView;
+ }
+
+ public void loadListDownloads() {
+ view.showLoading(true);
+ bookRepository.getDownloadedBooks(new BookDetailRepository.GetBooksForLanguageCallback() {
+ @Override
+ public void onBooksLoaded(List books) {
+ view.showLoading(false);
+ if (books.isEmpty() || books.size() == 0) {
+ view.showNoBooksDownloadedMessage();
+ return;
+ }
+ view.showDownloadedBooks(books);
+
+ }
+
+ @Override
+ public void onBooksLoadError(Exception e) {
+ view.showErrorScreen(true, e.getMessage(), true);
+ view.showLoading(false);
+ }
+ });
+ }
+
+ @Override
+ public void deleteDownload(BookDetail bookDetail) {
+ bookRepository.deleteBook(bookDetail, new BookDetailRepository.DeleteBookCallBack() {
+
+ @Override
+ public void onBookDeleted(BookDetail bookDetail) {
+ loadListDownloads();
+ }
+
+ @Override
+ public void onBookDeleteFailed(Exception e) {
+ view.showSnackBarError(e.getMessage());
+ }
+ });
+ }
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsViewHolder.java b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsViewHolder.java
new file mode 100644
index 0000000..2c39142
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/downloads/DownloadsViewHolder.java
@@ -0,0 +1,29 @@
+package org.bookdash.android.presentation.downloads;
+
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import org.bookdash.android.R;
+import org.bookdash.android.domain.pojo.BookDetail;
+
+public class DownloadsViewHolder extends RecyclerView.ViewHolder {
+ TextView downloadTitleTextView;
+ TextView downloadProgressTextView;
+ ImageView downloadImageTextView;
+ ImageButton downloadActionButtonView;
+ RelativeLayout downloadRelativeLayout;
+ BookDetail book;
+
+ public DownloadsViewHolder(View itemView) {
+ super(itemView);
+ downloadActionButtonView = (ImageButton) itemView.findViewById(R.id.image_button_delete_book);
+ downloadImageTextView = (ImageView) itemView.findViewById(R.id.image_view_download_book_cover);
+ downloadProgressTextView = (TextView) itemView.findViewById(R.id.download_progress);
+ downloadTitleTextView = (TextView) itemView.findViewById(R.id.text_view_book_title_download);
+ downloadRelativeLayout = (RelativeLayout)itemView.findViewById(R.id.download_relative_layout);
+ }
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/BookAdapter.java b/app/src/main/java/org/bookdash/android/presentation/listbooks/BookAdapter.java
index 0c1e70f..4fb012c 100644
--- a/app/src/main/java/org/bookdash/android/presentation/listbooks/BookAdapter.java
+++ b/app/src/main/java/org/bookdash/android/presentation/listbooks/BookAdapter.java
@@ -5,12 +5,15 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
+import android.widget.RelativeLayout;
import com.bumptech.glide.Glide;
import org.bookdash.android.R;
+import org.bookdash.android.domain.pojo.BookDetail;
+
import java.util.List;
-import org.bookdash.android.domain.pojo.*;
+
/**
* @author Rebecca Franks
* @since 2015/07/16 2:06 PM
@@ -21,7 +24,6 @@ public class BookAdapter extends RecyclerView.Adapter {
private View.OnClickListener onClickListener;
-
public BookAdapter(List bookDetails, Context context, View.OnClickListener onClickListener) {
this.bookDetails = bookDetails;
this.context = context;
@@ -30,7 +32,7 @@ public BookAdapter(List bookDetails, Context context, View.OnClickLi
@Override
public BookViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
+ int viewType) {
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.list_item_book, parent, false);
return new BookViewHolder(v);
@@ -40,12 +42,14 @@ public BookViewHolder onCreateViewHolder(ViewGroup parent,
public void onBindViewHolder(BookViewHolder holder, int position) {
BookDetail bookDetail = bookDetails.get(position);
holder.bookTitle.setText(bookDetail.getBookTitle());
- Glide.with(context).load(bookDetail.getBookCoverUrl()).into(holder.bookCover);
+ Glide.with(context).load(bookDetail.getBookCoverUrl()).placeholder(R.drawable.bookdash_placeholder).error(R.drawable.bookdash_placeholder).into(holder.bookCover);
holder.bookDetail = bookDetail;
holder.downloadedIcon.setVisibility(bookDetail.isDownloadedAlready() ? View.VISIBLE : View.INVISIBLE);
holder.cardContainer.setTag(holder);
holder.cardContainer.setOnClickListener(onClickListener);
-
+ // int width = holder.cardContainer.getMeasuredWidth();
+ /* holder.bookCover.setLayoutParams(new RelativeLayout.LayoutParams(width, width));
+ holder.bookCover.invalidate();*/
}
@Override
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/BookViewHolder.java b/app/src/main/java/org/bookdash/android/presentation/listbooks/BookViewHolder.java
index 298d271..bc15e22 100644
--- a/app/src/main/java/org/bookdash/android/presentation/listbooks/BookViewHolder.java
+++ b/app/src/main/java/org/bookdash/android/presentation/listbooks/BookViewHolder.java
@@ -15,7 +15,6 @@
*/
public class BookViewHolder extends RecyclerView.ViewHolder {
- public TextView author;
public TextView bookTitle;
public ImageView bookCover;
public CardView cardContainer;
@@ -27,7 +26,6 @@ public BookViewHolder(View v) {
cardContainer = (CardView) v.findViewById(R.id.card_view);
bookTitle = (TextView) v.findViewById(R.id.textViewBookName);
bookCover = (ImageView) v.findViewById(R.id.imageViewBookCover);
- author = (TextView) v.findViewById(R.id.textViewAuthor);
downloadedIcon = (ImageView) v.findViewById(R.id.imageViewBookDownloaded);
}
}
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksContract.java b/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksContract.java
index ccbf536..ebb30f2 100644
--- a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksContract.java
+++ b/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksContract.java
@@ -11,9 +11,6 @@
public interface ListBooksContract {
interface View {
- void showThanksPopover();
- void showAboutPage();
- void showRatingPlayStore();
void showErrorScreen(boolean show, String errorMessage, boolean showRetryButton);
void showLoading(boolean visible);
void showBooks(List bookDetailList);
@@ -23,8 +20,8 @@ interface View {
interface UserActionsListener {
void loadLanguages();
- void saveSelectedLanguage(int indexOfLanguage, boolean downloadOnly);
- void loadBooksForLanguagePreference(boolean downloadedOnly);
+ void saveSelectedLanguage(int indexOfLanguage);
+ void loadBooksForLanguagePreference();
void clickOpenLanguagePopover();
}
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksFragment.java b/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksFragment.java
new file mode 100644
index 0000000..f6cca56
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksFragment.java
@@ -0,0 +1,215 @@
+package org.bookdash.android.presentation.listbooks;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.Toolbar;
+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.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import org.bookdash.android.Injection;
+import org.bookdash.android.R;
+import org.bookdash.android.domain.pojo.BookDetail;
+import org.bookdash.android.presentation.bookinfo.BookInfoActivity;
+import org.bookdash.android.presentation.main.NavDrawerInterface;
+import org.bookdash.android.presentation.widget.SpacesItemDecoration;
+
+import java.util.List;
+
+import fr.castorflex.android.circularprogressbar.CircularProgressBar;
+
+
+public class ListBooksFragment extends Fragment implements ListBooksContract.View {
+
+ private static final String TAG = ListBooksFragment.class.getCanonicalName();
+ private static final int BOOK_DETAIL_REQUEST_CODE = 43;
+ private ListBooksContract.UserActionsListener actionsListener;
+ private Button buttonRetry;
+ private RecyclerView mRecyclerView;
+ private CircularProgressBar circularProgressBar;
+ private LinearLayout linearLayoutErrorScreen;
+ private TextView textViewErrorMessage;
+ private Toolbar toolbar;
+ private NavDrawerInterface navDrawerInterface;
+ private BookAdapter bookAdapter;
+
+ public static Fragment newInstance() {
+ return new ListBooksFragment();
+ }
+
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.fragment_list_books, container, false);
+ }
+
+ @Override
+ public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
+ super.onViewCreated(view, savedInstanceState);
+ actionsListener = new ListBooksPresenter(this, Injection.provideBookRepo(), Injection.provideSettingsRepo(getActivity()));
+
+ circularProgressBar = (CircularProgressBar) view.findViewById(R.id.activity_loading_books);
+ linearLayoutErrorScreen = (LinearLayout) view.findViewById(R.id.linear_layout_error);
+ buttonRetry = (Button) view.findViewById(R.id.button_retry);
+ textViewErrorMessage = (TextView) view.findViewById(R.id.text_view_error_screen);
+ mRecyclerView = (RecyclerView) view.findViewById(R.id.recycler_view_books);
+ mRecyclerView.setLayoutManager(new GridLayoutManager(getActivity(), getContext().getResources().getInteger(R.integer.book_span)));
+ mRecyclerView.setHasFixedSize(true);
+ mRecyclerView.addItemDecoration(new SpacesItemDecoration(getResources().getInteger(R.integer.list_books_space)));
+ buttonRetry.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ Log.d(TAG, "Retry button clicked");
+ actionsListener.loadBooksForLanguagePreference();
+ }
+ });
+ toolbar = (Toolbar) view.findViewById(R.id.toolbar);
+ if (navDrawerInterface != null) {
+ navDrawerInterface.setToolbar(toolbar);
+ }
+ final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
+
+
+ if (actionBar != null) {
+ actionBar.setHomeAsUpIndicator(R.drawable.ic_menu_black_24dp);
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ actionBar.setTitle(getString(R.string.book_dash));
+ }
+ actionsListener.loadLanguages();
+ actionsListener.loadBooksForLanguagePreference();
+ setHasOptionsMenu(true);
+ }
+
+
+ private View.OnClickListener bookClickListener = new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ openBookDetails(v);
+ }
+ };
+
+
+ public void openBookDetails(View v) {
+ Intent intent = new Intent(getActivity(), BookInfoActivity.class);
+ // intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ BookViewHolder viewHolder = (BookViewHolder) v.getTag();
+ BookDetail bookDetailResult = viewHolder.bookDetail;
+ intent.putExtra(BookInfoActivity.BOOK_PARCEL, bookDetailResult.toBookParcelable());
+ startActivityForResult(intent, BOOK_DETAIL_REQUEST_CODE);
+
+ }
+
+ @Override
+ public void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+ Log.d(TAG, "onActivityResult() called with: " + "requestCode = [" + requestCode + "], resultCode = [" + resultCode + "], data = [" + data + "]");
+
+ if (requestCode == BOOK_DETAIL_REQUEST_CODE) {
+ if (bookAdapter != null) {
+ bookAdapter.notifyDataSetChanged();
+ }
+ }
+ }
+
+ @Override
+ public void showErrorScreen(boolean show, String errorMessage, boolean showRetryButton) {
+ if (show) {
+ linearLayoutErrorScreen.setVisibility(View.VISIBLE);
+ } else {
+ linearLayoutErrorScreen.setVisibility(View.GONE);
+ }
+ buttonRetry.setVisibility(showRetryButton ? View.VISIBLE : View.GONE);
+ textViewErrorMessage.setText(errorMessage);
+
+ }
+
+ @Override
+ public void showLoading(boolean visible) {
+ circularProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE);
+ mRecyclerView.setVisibility(visible ? View.GONE : View.VISIBLE);
+
+ }
+
+ @Override
+ public void showBooks(List bookDetailList) {
+ if (bookDetailList.isEmpty()) {
+ showErrorScreen(true, getString(R.string.no_books_available), true);
+ }
+ bookAdapter = new BookAdapter(bookDetailList, ListBooksFragment.this.getActivity(), bookClickListener);
+ mRecyclerView.setAdapter(bookAdapter);
+
+ }
+
+ @Override
+ public void showSnackBarError(int message) {
+ Snackbar.make(mRecyclerView, message, Snackbar.LENGTH_LONG).show();
+ }
+
+ private DialogInterface.OnClickListener languageClickListener = new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialog, int which) {
+ if (dialog != null) {
+ dialog.dismiss();
+ }
+
+ actionsListener.saveSelectedLanguage(which);
+
+ }
+ };
+
+ @Override
+ public void showLanguagePopover(String[] languages, int selected) {
+ AlertDialog alertDialogLanguages = new AlertDialog.Builder(getActivity())
+ .setTitle(getString(R.string.language_selection_heading))
+ .setSingleChoiceItems(languages, selected, languageClickListener).create();
+ alertDialogLanguages.show();
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ if (context instanceof NavDrawerInterface) {
+ navDrawerInterface = (NavDrawerInterface) context;
+
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ super.onDetach();
+ navDrawerInterface = null;
+ }
+
+ @Override
+ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+ super.onCreateOptionsMenu(menu, inflater);
+ inflater.inflate(R.menu.menu_main, menu);
+ }
+
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ if (item.getItemId() == R.id.action_language_choice) {
+ actionsListener.clickOpenLanguagePopover();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksPresenter.java b/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksPresenter.java
index f24280f..59d1e2e 100644
--- a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksPresenter.java
+++ b/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksPresenter.java
@@ -25,16 +25,17 @@ public ListBooksPresenter(ListBooksContract.View listBooksView, BookDetailReposi
this.bookDetailRepository = bookDetailRepository;
this.settingsRepository = settingsRepository;
}
+
@Override
- public void loadBooksForLanguagePreference(boolean downloadedOnly) {
+ public void loadBooksForLanguagePreference() {
String languagePreference = settingsRepository.getLanguagePreference();
- loadBooksForLanguage(languagePreference, downloadedOnly);
+ loadBooksForLanguage(languagePreference);
}
- private void loadBooksForLanguage(String language, boolean downloadedOnly) {
+ private void loadBooksForLanguage(String language) {
listBooksView.showLoading(true);
listBooksView.showErrorScreen(false, "", false);
- bookDetailRepository.getBooksForLanguage(language,downloadedOnly, new BookDetailRepository.GetBooksForLanguageCallback() {
+ bookDetailRepository.getBooksForLanguage(language, new BookDetailRepository.GetBooksForLanguageCallback() {
@Override
public void onBooksLoaded(List books) {
listBooksView.showLoading(false);
@@ -69,10 +70,10 @@ public void onLanguagesLoadError(Exception e) {
}
@Override
- public void saveSelectedLanguage(int indexOfLanguage, boolean downloadOnly) {
+ public void saveSelectedLanguage(int indexOfLanguage) {
settingsRepository.saveLanguagePreference(languages.get(indexOfLanguage).getLanguageName());
- loadBooksForLanguage(languages.get(indexOfLanguage).getLanguageName(), downloadOnly);
+ loadBooksForLanguage(languages.get(indexOfLanguage).getLanguageName());
}
@Override
@@ -95,5 +96,4 @@ public void clickOpenLanguagePopover() {
}
-
}
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/SquareImageView.java b/app/src/main/java/org/bookdash/android/presentation/listbooks/SquareImageView.java
new file mode 100644
index 0000000..86eb30f
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/listbooks/SquareImageView.java
@@ -0,0 +1,21 @@
+package org.bookdash.android.presentation.listbooks;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.ImageView;
+
+
+public class SquareImageView extends ImageView {
+ public SquareImageView(Context context) {
+ super(context);
+ }
+
+ public SquareImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onMeasure(int widthSpec, int heightSpec) {
+ super.onMeasure(widthSpec, widthSpec);
+ }
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksActivity.java b/app/src/main/java/org/bookdash/android/presentation/main/MainActivity.java
similarity index 52%
rename from app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksActivity.java
rename to app/src/main/java/org/bookdash/android/presentation/main/MainActivity.java
index 9186f50..b4b9bd0 100644
--- a/app/src/main/java/org/bookdash/android/presentation/listbooks/ListBooksActivity.java
+++ b/app/src/main/java/org/bookdash/android/presentation/main/MainActivity.java
@@ -1,30 +1,26 @@
-package org.bookdash.android.presentation.listbooks;
+package org.bookdash.android.presentation.main;
import android.content.ActivityNotFoundException;
-import android.content.DialogInterface;
import android.content.Intent;
-import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.NavigationView;
import android.support.design.widget.Snackbar;
+import android.support.v4.app.Fragment;
+import android.support.v4.app.FragmentManager;
+import android.support.v4.app.FragmentTransaction;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBar;
import android.support.v7.app.AlertDialog;
-import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
-import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
import android.widget.TextView;
-
import com.google.android.gms.appinvite.AppInvite;
import com.google.android.gms.appinvite.AppInviteInvitation;
import com.google.android.gms.appinvite.AppInviteInvitationResult;
@@ -33,38 +29,31 @@
import com.google.android.gms.common.api.ResultCallback;
import org.bookdash.android.BuildConfig;
-import org.bookdash.android.Injection;
import org.bookdash.android.R;
-import org.bookdash.android.presentation.about.AboutActivity;
+import org.bookdash.android.presentation.about.AboutFragment;
import org.bookdash.android.presentation.activity.BaseAppCompatActivity;
-import org.bookdash.android.presentation.bookinfo.BookInfoActivity;
-import org.bookdash.android.domain.pojo.BookDetail;
-import org.bookdash.android.presentation.view.AutofitRecyclerView;
-
-import java.util.List;
-
-import fr.castorflex.android.circularprogressbar.CircularProgressBar;
+import org.bookdash.android.presentation.downloads.DownloadsFragment;
+import org.bookdash.android.presentation.listbooks.ListBooksFragment;
-public class ListBooksActivity extends BaseAppCompatActivity implements ListBooksContract.View {
+public class MainActivity extends BaseAppCompatActivity implements MainContract.MainView, NavDrawerInterface {
private static final int INVITE_REQUEST_CODE = 1;
- private ListBooksContract.UserActionsListener actionsListener;
+ private static final String TAG = "MainActivity";
private GoogleApiClient googleApiClient;
- private Toolbar toolbar;
private DrawerLayout drawerLayout;
private NavigationView navigationView;
- private Button buttonRetry;
+ private MainContract.MainUserActions actionsListener;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
- actionsListener = new ListBooksPresenter(this, Injection.provideBookRepo(), Injection.provideSettingsRepo(this));
drawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
- toolbar = (Toolbar) findViewById(R.id.toolbar);
+
navigationView = (NavigationView) findViewById(R.id.navigation_view);
- setSupportActionBar(toolbar);
+
+ actionsListener = new MainPresenter(this);
final ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
@@ -73,46 +62,12 @@ protected void onCreate(Bundle savedInstanceState) {
}
setUpNavDrawer();
- circularProgressBar = (CircularProgressBar) findViewById(R.id.activity_loading_books);
- linearLayoutErrorScreen = (LinearLayout) findViewById(R.id.linear_layout_error);
- buttonRetry = (Button) findViewById(R.id.button_retry);
- textViewErrorMessage = (TextView) findViewById(R.id.text_view_error_screen);
- mRecyclerView = (AutofitRecyclerView) findViewById(R.id.recycler_view_books);
-
- mRecyclerView.setHasFixedSize(true);
- mRecyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
- @Override
- public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
- outRect.bottom = 8;
- outRect.right = 8;
- outRect.left = 8;
- outRect.top = 8;
- }
- });
- buttonRetry.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Log.d(TAG, "Retry button clicked");
- actionsListener.loadBooksForLanguagePreference(false);
- }
- });
-
- actionsListener.loadLanguages();
- actionsListener.loadBooksForLanguagePreference(false);
checkIfComingFromInvite();
+ showAllBooks();
}
private void setUpNavDrawer() {
- if (toolbar != null) {
- getSupportActionBar().setDisplayHomeAsUpEnabled(true);
- toolbar.setNavigationOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- drawerLayout.openDrawer(GravityCompat.START);
- }
- });
- }
navigationView.setCheckedItem(R.id.action_all_books);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
@@ -158,14 +113,11 @@ public boolean onNavigationItemSelected(MenuItem menuItem) {
}
private void showDownloadedBooks() {
- downloadOnly = true;
-
- actionsListener.loadBooksForLanguagePreference(downloadOnly);
+ actionsListener.clickViewDownloadBooks();
}
private void showAllBooks() {
- downloadOnly = false;
- actionsListener.loadBooksForLanguagePreference(downloadOnly);
+ actionsListener.clickViewAllBooks();
}
private void showSettingsScreen() {
@@ -182,13 +134,6 @@ public void onConnectionFailed(ConnectionResult connectionResult) {
}
})
- /* .enableAutoManage(this, new GoogleApiClient.OnConnectionFailedListener() {
- @Override
- public void onConnectionFailed(ConnectionResult connectionResult) {
- Log.d(TAG, "onConnectionFailed: onResult:" + connectionResult.toString());
-
- }
- })*/
.build();
if (googleApiClient != null) {
googleApiClient.connect();
@@ -204,12 +149,6 @@ public void onResult(AppInviteInvitationResult result) {
}
}
- private static final String TAG = ListBooksActivity.class.getCanonicalName();
-
- private AutofitRecyclerView mRecyclerView;
- private CircularProgressBar circularProgressBar;
- private LinearLayout linearLayoutErrorScreen;
- private TextView textViewErrorMessage;
@Override
protected void onStop() {
@@ -229,26 +168,12 @@ protected void onStart() {
}
}
- private View.OnClickListener bookClickListener = new View.OnClickListener() {
- @Override
- public void onClick(View v) {
-
- // final BookDetail bookDetail = (BookDetail) v.getTag();
-
- openBookDetails(v);
- }
- };
@Override
- protected String getScreenName() {
- return "BookListingScreen";
+ public String getScreenName() {
+ return "MainActivity";
}
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return true;
- }
@Override
public boolean onOptionsItemSelected(MenuItem item) {
@@ -259,10 +184,6 @@ public boolean onOptionsItemSelected(MenuItem item) {
showAboutPage();
return true;
}
- if (id == R.id.action_language_choice) {
- actionsListener.clickOpenLanguagePopover();
- return true;
- }
if (id == R.id.action_rate_app) {
showRatingPlayStore();
return true;
@@ -287,7 +208,7 @@ private void openInvitePage() {
.build();
startActivityForResult(intent, INVITE_REQUEST_CODE);
} catch (ActivityNotFoundException ac) {
- Snackbar.make(mRecyclerView, R.string.common_google_play_services_api_unavailable_text, Snackbar.LENGTH_LONG).show();
+ Snackbar.make(navigationView, R.string.common_google_play_services_api_unavailable_text, Snackbar.LENGTH_LONG).show();
}
}
@@ -311,34 +232,6 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
}
}
- private boolean downloadOnly = false;
- private DialogInterface.OnClickListener languageClickListener = new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- if (dialog != null) {
- dialog.dismiss();
- }
-
- actionsListener.saveSelectedLanguage(which, downloadOnly);
-
- /* tracker.send(new HitBuilders.EventBuilder()
- .setCategory("LanguageChange")
- .setAction(languages.get(which).getLanguageName())
- .build());*/
-
-
- }
- };
-
- @Override
- public void showLanguagePopover(String[] languages, int selected) {
- AlertDialog alertDialogLanguages = new AlertDialog.Builder(this)
- .setTitle(getString(R.string.language_selection_heading))
- .setSingleChoiceItems(languages, selected, languageClickListener).create();
- alertDialogLanguages.show();
- }
-
-
@Override
public void showThanksPopover() {
AlertDialog.Builder thanksDialog = new AlertDialog.Builder(this);
@@ -353,39 +246,11 @@ public void showThanksPopover() {
@Override
public void showAboutPage() {
- Intent intent = new Intent(ListBooksActivity.this, AboutActivity.class);
-
- startActivity(intent);
- }
-
-
- public void openBookDetails(View v) {
- /* if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP) {
- ImageView imageView =
- ((BookViewHolder) v.getTag()).bookCover;
- imageView.setTransitionName(getString(R.string.transition_book));
- v.setBackgroundColor(
- ContextCompat.getColor(ListBooksActivity.this, android.R.color.transparent));
- ActivityOptions options =
- ActivityOptions.makeSceneTransitionAnimation(ListBooksActivity.this,
- Pair.create((View) imageView, getString(R.string.transition_book)));
-
-
- Intent intent = new Intent(ListBooksActivity.this, BookInfoActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.putExtra(BookInfoActivity.BOOK_PARCEL, ((BookViewHolder) v.getTag()).bookDetail.toBookParcelable());
- startActivity(intent, options.toBundle());
-
- } else {*/
-
- Intent intent = new Intent(ListBooksActivity.this, BookInfoActivity.class);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- BookViewHolder viewHolder = (BookViewHolder) v.getTag();
- BookDetail bookDetailResult = viewHolder.bookDetail;
- intent.putExtra(BookInfoActivity.BOOK_PARCEL, bookDetailResult.toBookParcelable());
- startActivity(intent);
-
- /* }*/
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ Fragment f = AboutFragment.newInstance();
+ ft.replace(R.id.fragment_content, f, "ABOUT");
+ ft.commit();
}
@Override
@@ -403,44 +268,42 @@ public void showRatingPlayStore() {
}
@Override
- public void showErrorScreen(boolean show, String errorMessage, boolean showRetryButton) {
- if (show) {
- linearLayoutErrorScreen.setVisibility(View.VISIBLE);
- } else {
- linearLayoutErrorScreen.setVisibility(View.GONE);
- }
- buttonRetry.setVisibility(showRetryButton ? View.VISIBLE : View.GONE);
- textViewErrorMessage.setText(errorMessage);
-
+ public void showAllBooksPage() {
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ Fragment f = ListBooksFragment.newInstance();
+ ft.replace(R.id.fragment_content, f, "ALLBOOKS");
+ ft.commit();
}
@Override
- public void showLoading(boolean visible) {
- circularProgressBar.setVisibility(visible ? View.VISIBLE : View.GONE);
- mRecyclerView.setVisibility(visible ? View.GONE : View.VISIBLE);
-
+ public void showDownloadedBooksPage() {
+ FragmentManager fragmentManager = getSupportFragmentManager();
+ FragmentTransaction ft = fragmentManager.beginTransaction();
+ Fragment f = DownloadsFragment.newInstance();
+ ft.replace(R.id.fragment_content, f, "DOWNLOADED_BOOKS");
+ ft.commit();
}
- @Override
- public void showBooks(List bookDetailList) {
- if (bookDetailList.isEmpty()) {
- if (downloadOnly) {
- showErrorScreen(true, getString(R.string.no_books_downloaded), false);
-
- } else {
- showErrorScreen(true, getString(R.string.no_books_available), true);
- }
- // return;
- }
- RecyclerView.Adapter mAdapter = new BookAdapter(bookDetailList, ListBooksActivity.this, bookClickListener);
- mRecyclerView.setAdapter(mAdapter);
- mRecyclerView.scheduleLayoutAnimation();
+ @Override
+ public void openNavDrawer() {
+ drawerLayout.openDrawer(navigationView);
}
@Override
- public void showSnackBarError(int message) {
- Snackbar.make(mRecyclerView, message, Snackbar.LENGTH_LONG).show();
+ public void closeNavDrawer() {
+ drawerLayout.closeDrawer(navigationView);
}
-}
+ @Override
+ public void setToolbar(Toolbar toolbar) {
+ setSupportActionBar(toolbar);
+ toolbar.setNavigationOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ drawerLayout.openDrawer(GravityCompat.START);
+ }
+ });
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/org/bookdash/android/presentation/main/MainContract.java b/app/src/main/java/org/bookdash/android/presentation/main/MainContract.java
new file mode 100644
index 0000000..836fd40
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/main/MainContract.java
@@ -0,0 +1,25 @@
+package org.bookdash.android.presentation.main;
+
+
+public interface MainContract {
+ interface MainView {
+
+ void showThanksPopover();
+
+ void showAboutPage();
+
+ void showRatingPlayStore();
+
+ void showAllBooksPage();
+
+ void showDownloadedBooksPage();
+ }
+
+ interface MainUserActions {
+
+ void clickViewDownloadBooks();
+
+ void clickViewAllBooks();
+ }
+}
+
diff --git a/app/src/main/java/org/bookdash/android/presentation/main/MainPresenter.java b/app/src/main/java/org/bookdash/android/presentation/main/MainPresenter.java
new file mode 100644
index 0000000..fdac318
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/main/MainPresenter.java
@@ -0,0 +1,30 @@
+package org.bookdash.android.presentation.main;
+
+import org.bookdash.android.data.settings.SettingsApi;
+import org.bookdash.android.domain.pojo.Language;
+
+import java.util.List;
+
+/**
+ * Created by rebeccafranks on 16/04/19.
+ */
+public class MainPresenter implements MainContract.MainUserActions {
+
+ private MainContract.MainView mainView;
+
+ public MainPresenter(MainContract.MainView mainView) {
+ this.mainView = mainView;
+ }
+
+ @Override
+ public void clickViewDownloadBooks() {
+ mainView.showDownloadedBooksPage();
+ }
+
+ @Override
+ public void clickViewAllBooks() {
+ mainView.showAllBooksPage();
+ }
+
+
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/main/NavDrawerInterface.java b/app/src/main/java/org/bookdash/android/presentation/main/NavDrawerInterface.java
new file mode 100644
index 0000000..47bedb6
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/main/NavDrawerInterface.java
@@ -0,0 +1,12 @@
+package org.bookdash.android.presentation.main;
+
+import android.support.v7.widget.Toolbar;
+
+
+public interface NavDrawerInterface {
+ void openNavDrawer();
+
+ void closeNavDrawer();
+
+ void setToolbar(Toolbar toolbar);
+}
diff --git a/app/src/main/java/org/bookdash/android/presentation/splash/SplashActivity.java b/app/src/main/java/org/bookdash/android/presentation/splash/SplashActivity.java
index 7b23df1..91472c0 100644
--- a/app/src/main/java/org/bookdash/android/presentation/splash/SplashActivity.java
+++ b/app/src/main/java/org/bookdash/android/presentation/splash/SplashActivity.java
@@ -7,7 +7,8 @@
import org.bookdash.android.Injection;
import org.bookdash.android.R;
-import org.bookdash.android.presentation.listbooks.ListBooksActivity;
+import org.bookdash.android.presentation.listbooks.ListBooksFragment;
+import org.bookdash.android.presentation.main.MainActivity;
import za.co.riggaroo.materialhelptutorial.tutorial.MaterialTutorialActivity;
@@ -47,7 +48,7 @@ public void loadTutorial() {
@Override
public void loadMainScreen() {
- Intent mainAct = new Intent(SplashActivity.this, ListBooksActivity.class);
+ Intent mainAct = new Intent(SplashActivity.this, MainActivity.class);
startActivity(mainAct);
finish();
}
diff --git a/app/src/main/java/org/bookdash/android/presentation/widget/SpacesItemDecoration.java b/app/src/main/java/org/bookdash/android/presentation/widget/SpacesItemDecoration.java
new file mode 100644
index 0000000..a980444
--- /dev/null
+++ b/app/src/main/java/org/bookdash/android/presentation/widget/SpacesItemDecoration.java
@@ -0,0 +1,21 @@
+package org.bookdash.android.presentation.widget;
+
+import android.graphics.Rect;
+import android.support.v7.widget.RecyclerView;
+import android.view.View;
+
+public class SpacesItemDecoration extends RecyclerView.ItemDecoration {
+ private int space;
+
+ public SpacesItemDecoration(int space) {
+ this.space = space;
+ }
+
+ @Override
+ public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
+ outRect.left = space;
+ outRect.right = space;
+ outRect.bottom = space;
+ outRect.top = space;
+ }
+}
diff --git a/app/src/main/kotlin/org.bookdash.android/data/BookDetailRepositoryExtenstion.kt b/app/src/main/kotlin/org.bookdash.android/data/BookDetailRepositoryExtenstion.kt
deleted file mode 100644
index e69de29..0000000
diff --git a/app/src/main/res/drawable-hdpi/bookdash_placeholder.png b/app/src/main/res/drawable-hdpi/bookdash_placeholder.png
new file mode 100644
index 0000000..e8f219e
Binary files /dev/null and b/app/src/main/res/drawable-hdpi/bookdash_placeholder.png differ
diff --git a/app/src/main/res/drawable-v21/download_selector.xml b/app/src/main/res/drawable-v21/download_selector.xml
new file mode 100644
index 0000000..502f203
--- /dev/null
+++ b/app/src/main/res/drawable-v21/download_selector.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/download_selector.xml b/app/src/main/res/drawable/download_selector.xml
new file mode 100644
index 0000000..09eca7d
--- /dev/null
+++ b/app/src/main/res/drawable/download_selector.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml b/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml
new file mode 100644
index 0000000..99b5867
--- /dev/null
+++ b/app/src/main/res/drawable/ic_chrome_reader_mode_black_24dp.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_delete.xml b/app/src/main/res/drawable/ic_delete.xml
new file mode 100644
index 0000000..39e64d6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_file_download_black.xml b/app/src/main/res/drawable/ic_file_download_black.xml
new file mode 100644
index 0000000..492b41d
--- /dev/null
+++ b/app/src/main/res/drawable/ic_file_download_black.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/layout-land/activity_book_information.xml b/app/src/main/res/layout-land/activity_book_information.xml
index d4d5763..43c26bf 100644
--- a/app/src/main/res/layout-land/activity_book_information.xml
+++ b/app/src/main/res/layout-land/activity_book_information.xml
@@ -101,10 +101,11 @@
diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml
index ee60dcc..a470906 100644
--- a/app/src/main/res/layout/activity_about.xml
+++ b/app/src/main/res/layout/activity_about.xml
@@ -2,22 +2,25 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
+ android:fitsSystemWindows="true"
android:layout_height="match_parent">
@@ -27,6 +30,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/nestedScrollView"
+ android:fitsSystemWindows="true"
android:layout_marginTop="?attr/actionBarSize"
android:background="@color/light_gray_background">
diff --git a/app/src/main/res/layout/activity_book_information.xml b/app/src/main/res/layout/activity_book_information.xml
index 8e738a2..b05e5b6 100644
--- a/app/src/main/res/layout/activity_book_information.xml
+++ b/app/src/main/res/layout/activity_book_information.xml
@@ -1,22 +1,23 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
-
+
-
+
+ type="View.OnClickListener"/>
+ type="org.bookdash.android.domain.pojo.BookDetail"/>
@@ -26,7 +27,6 @@
android:layout_height="match_parent">
+ app:cpb_sweep_speed="1.0"/>
+ android:src="@drawable/lb_ic_sad_cloud"/>
+ android:text="@string/error_loading_books"/>
+ android:text="@string/button_retry_text"/>
+ app:layout_collapseParallaxMultiplier="0.7"/>
+ android:layout_height="match_parent"/>
+ app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
@@ -166,7 +166,7 @@
android:gravity="center_vertical"
android:text="@string/about_book_info"
android:textColor="@color/text_secondary_dark"
- android:textSize="14sp" />
+ android:textSize="14sp"/>
+ android:textSize="14sp"/>
@@ -196,7 +196,7 @@
android:fontFamily="sans-serif"
android:text="@{book_info.aboutBook}"
android:textColor="@color/text_color_primary_dark"
- android:textSize="16sp" />
+ android:textSize="16sp"/>
@@ -227,7 +227,7 @@
android:gravity="center_vertical"
android:text="@string/contributors"
android:textColor="@color/text_secondary_dark"
- android:textSize="14sp" />
+ android:textSize="14sp"/>
+ app:layout_anchorGravity="bottom|right|end"/>
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index cc0d2ca..c35e91b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -1,114 +1,26 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:id="@+id/drawer_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ app:menu="@menu/menu_drawer"/>
diff --git a/app/src/main/res/layout/fragment_downloads.xml b/app/src/main/res/layout/fragment_downloads.xml
new file mode 100644
index 0000000..5f652b3
--- /dev/null
+++ b/app/src/main/res/layout/fragment_downloads.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_list_books.xml b/app/src/main/res/layout/fragment_list_books.xml
new file mode 100644
index 0000000..dd412af
--- /dev/null
+++ b/app/src/main/res/layout/fragment_list_books.xml
@@ -0,0 +1,100 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/list_item_book.xml b/app/src/main/res/layout/list_item_book.xml
index 082ceab..8b79cb5 100644
--- a/app/src/main/res/layout/list_item_book.xml
+++ b/app/src/main/res/layout/list_item_book.xml
@@ -1,81 +1,63 @@
+ xmlns:app="http://schemas.android.com/apk/res-auto"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="4dp"
+ >
+ app:cardCornerRadius="2dp">
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
-
-
-
+ android:src="@drawable/bookdash_placeholder"/>
+ android:textColor="#212121"
+ android:textSize="16sp"
+ tools:text="Giraff really long named giraffee"/>
-
+ android:layout_alignParentRight="true"
+ android:layout_margin="4dp"
+ app:srcCompat="@drawable/ic_cloud_download_black_24dp"
+ android:tint="@color/colorAccent"
+ android:foregroundGravity="bottom|right"/>
diff --git a/app/src/main/res/layout/list_item_download.xml b/app/src/main/res/layout/list_item_download.xml
new file mode 100644
index 0000000..431531a
--- /dev/null
+++ b/app/src/main/res/layout/list_item_download.xml
@@ -0,0 +1,82 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values-land/integers.xml b/app/src/main/res/values-land/integers.xml
new file mode 100644
index 0000000..cf7c880
--- /dev/null
+++ b/app/src/main/res/values-land/integers.xml
@@ -0,0 +1,5 @@
+
+
+
+ 3
+
\ No newline at end of file
diff --git a/app/src/main/res/values-sw600dp-port/integers.xml b/app/src/main/res/values-sw600dp-port/integers.xml
new file mode 100644
index 0000000..0c84331
--- /dev/null
+++ b/app/src/main/res/values-sw600dp-port/integers.xml
@@ -0,0 +1,4 @@
+
+
+ 3
+
\ No newline at end of file
diff --git a/app/src/main/res/values-sw600dp/integers.xml b/app/src/main/res/values-sw600dp/integers.xml
new file mode 100644
index 0000000..719fc40
--- /dev/null
+++ b/app/src/main/res/values-sw600dp/integers.xml
@@ -0,0 +1,4 @@
+
+
+ 5
+
\ No newline at end of file
diff --git a/app/src/main/res/values-v21/styles.xml b/app/src/main/res/values-v21/styles.xml
new file mode 100644
index 0000000..b9f9744
--- /dev/null
+++ b/app/src/main/res/values-v21/styles.xml
@@ -0,0 +1,27 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 5fa8e6b..c7b49ec 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -24,4 +24,7 @@
#ea2d6d
#fafafa
+ #616161
+ #e0e0e0
+ #e0e0e0
\ No newline at end of file
diff --git a/app/src/main/res/values/integers.xml b/app/src/main/res/values/integers.xml
new file mode 100644
index 0000000..8effea6
--- /dev/null
+++ b/app/src/main/res/values/integers.xml
@@ -0,0 +1,6 @@
+
+
+ 2
+
+ 8
+
\ 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 e1ec4a3..f8146b8 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -82,5 +82,10 @@
No books are downloaded. Head to the \"All Books\" section to download some!
No books available at the moment. Check back soon!
Book information is still loading...
+ Downloads
+ Delete Downloaded Book
+ Are you sure you want to delete \'%s\'?
+ Delete
+ Cancel
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index ace7ddd..d0670ef 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -15,13 +15,7 @@
- @color/default_background_colour
- @color/default_background_colour
- false
- - true
-
- - true
- - true
-
#eeeeee
+
+
diff --git a/app/src/mock/AndroidManifest.xml b/app/src/mock/AndroidManifest.xml
new file mode 100644
index 0000000..4bf6091
--- /dev/null
+++ b/app/src/mock/AndroidManifest.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/mock/java/org.bookdash.android/data/books/FakeBookDetailApiImpl.java b/app/src/mock/java/org.bookdash.android/data/books/FakeBookDetailApiImpl.java
index d5d72dd..77ac5d7 100644
--- a/app/src/mock/java/org.bookdash.android/data/books/FakeBookDetailApiImpl.java
+++ b/app/src/mock/java/org.bookdash.android/data/books/FakeBookDetailApiImpl.java
@@ -73,6 +73,11 @@ public void getBooksForLanguages(String language, BookServiceCallback> bookServiceCallback) {
+ //TODO
+ }
+
@Override
public void getBookDetail(String bookDetailId, BookServiceCallback bookServiceCallback) {
if (shouldFailService) {
@@ -110,4 +115,9 @@ public void getLanguages(BookServiceCallback> languagesCallback)
public void downloadBook(BookDetail bookDetail, BookServiceCallback downloadBookCallback, BookServiceProgressCallback bookServiceProgressCallback) {
}
+
+ @Override
+ public void deleteBook(BookDetail bookDetail, BookServiceCallback deleteBook) {
+
+ }
}
diff --git a/app/src/test/java/org/bookdash/android/data/books/BookDetailRepositoryImplTest.java b/app/src/test/java/org/bookdash/android/data/books/BookDetailRepositoryImplTest.java
index 7647c84..2f156d2 100644
--- a/app/src/test/java/org/bookdash/android/data/books/BookDetailRepositoryImplTest.java
+++ b/app/src/test/java/org/bookdash/android/data/books/BookDetailRepositoryImplTest.java
@@ -34,7 +34,7 @@ public void setup(){
private List BOOKS;
@Test
public void getBooksForLanguageApiSuccess(){
- bookDetailRepository.getBooksForLanguage("EN", false, booksForLanguageCallback);
+ bookDetailRepository.getBooksForLanguage("EN", booksForLanguageCallback);
// verify(bookDetailApi).getBooksForLanguages("EN", any(BookDetailApi.BookServiceCallback.class));
}
diff --git a/app/src/test/java/org/bookdash/android/presentation/downloads/DownloadsPresenterTest.java b/app/src/test/java/org/bookdash/android/presentation/downloads/DownloadsPresenterTest.java
new file mode 100644
index 0000000..4fbd7d8
--- /dev/null
+++ b/app/src/test/java/org/bookdash/android/presentation/downloads/DownloadsPresenterTest.java
@@ -0,0 +1,104 @@
+package org.bookdash.android.presentation.downloads;
+
+import com.parse.ParseObject;
+
+import org.bookdash.android.data.books.BookDetailRepository;
+import org.bookdash.android.domain.pojo.BookDetail;
+import org.bookdash.android.domain.pojo.Language;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.verify;
+
+
+public class DownloadsPresenterTest {
+ @Mock
+ private BookDetailRepository bookRepository;
+
+ private DownloadsPresenter downloadsPresenter;
+
+ @Mock
+ private DownloadsContract.View downloadsView;
+ @Captor
+ private ArgumentCaptor bookloadedCaptor;
+ @Captor
+ private ArgumentCaptor deleteBookCallBackArgumentCaptor;
+ private Language language;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ ParseObject.registerSubclass(Language.class);
+ ParseObject.registerSubclass(BookDetail.class);
+ downloadsPresenter = new DownloadsPresenter(bookRepository, downloadsView);
+ language = new Language("English", "EN", "1");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+
+ }
+
+ private List BOOKS = new ArrayList<>();
+
+ @Test
+ public void testGetListDownloads_ReturnsDownloads() {
+
+ downloadsPresenter.loadListDownloads();
+ verify(downloadsView).showLoading(true);
+ verify(bookRepository).getDownloadedBooks(bookloadedCaptor.capture());
+ BOOKS.add(new BookDetail("test title", "test", "2", language));
+ bookloadedCaptor.getValue().onBooksLoaded(BOOKS);
+
+ verify(downloadsView).showLoading(false);
+ verify(downloadsView).showDownloadedBooks(BOOKS);
+ }
+
+ @Test
+ public void testGetListDownloads_Error_ReturnsErrorMessage() {
+ downloadsPresenter.loadListDownloads();
+ verify(downloadsView).showLoading(true);
+ verify(bookRepository).getDownloadedBooks(bookloadedCaptor.capture());
+ bookloadedCaptor.getValue().onBooksLoadError(new Exception("Blah books didn't load"));
+
+ verify(downloadsView).showLoading(false);
+ verify(downloadsView).showErrorScreen(true, "Blah books didn't load", true);
+ }
+
+ @Test
+ public void testDeleteDownload_RemovesDownload() {
+ BookDetail bookDetail = new BookDetail("Fake Book", "http://test.com", "123", language);
+ downloadsPresenter.deleteDownload(bookDetail);
+
+ verify(bookRepository).deleteBook(any(BookDetail.class), deleteBookCallBackArgumentCaptor.capture());
+ deleteBookCallBackArgumentCaptor.getValue().onBookDeleted(bookDetail);
+
+ verify(bookRepository).getDownloadedBooks(bookloadedCaptor.capture());
+ bookloadedCaptor.getValue().onBooksLoaded(BOOKS);
+
+ verify(downloadsView).showNoBooksDownloadedMessage();
+ }
+
+ @Test
+ public void testDeleteDownload_RemovesDownloadKeepsOthers() {
+ BookDetail bookDetail = new BookDetail("Fake Book", "http://test.com", "123", language);
+ downloadsPresenter.deleteDownload(bookDetail);
+
+ verify(bookRepository).deleteBook(any(BookDetail.class), deleteBookCallBackArgumentCaptor.capture());
+ deleteBookCallBackArgumentCaptor.getValue().onBookDeleted(bookDetail);
+ BOOKS.add(new BookDetail("test title", "book cover", "23", new Language()));
+ verify(bookRepository).getDownloadedBooks(bookloadedCaptor.capture());
+ bookloadedCaptor.getValue().onBooksLoaded(BOOKS);
+
+ verify(downloadsView).showDownloadedBooks(BOOKS);
+ }
+}
\ No newline at end of file
diff --git a/app/src/test/java/org/bookdash/android/presentation/listbooks/ListBooksPresenterTest.java b/app/src/test/java/org/bookdash/android/presentation/listbooks/ListBooksPresenterTest.java
index 83642bc..96e8aec 100644
--- a/app/src/test/java/org/bookdash/android/presentation/listbooks/ListBooksPresenterTest.java
+++ b/app/src/test/java/org/bookdash/android/presentation/listbooks/ListBooksPresenterTest.java
@@ -60,8 +60,8 @@ public void setupListBooksPresenter() {
public void loadBooksSuccessfulLoadIntoView() {
when(settingsRepository.getLanguagePreference()).thenReturn("EN");
- listBooksPresenter.loadBooksForLanguagePreference(false);
- verify(bookRepository).getBooksForLanguage(eq("EN"), eq(false), booksForLanguageCallbackArgumentCaptor.capture());
+ listBooksPresenter.loadBooksForLanguagePreference();
+ verify(bookRepository).getBooksForLanguage(eq("EN"), booksForLanguageCallbackArgumentCaptor.capture());
booksForLanguageCallbackArgumentCaptor.getValue().onBooksLoaded(BOOKS);
verify(listBookView).showBooks(BOOKS);
@@ -72,9 +72,9 @@ public void loadBooksSuccessfulLoadIntoView() {
public void loadBooksLoadErrorShowErrorRetryScreen() {
when(settingsRepository.getLanguagePreference()).thenReturn("EN");
- listBooksPresenter.loadBooksForLanguagePreference(false);
+ listBooksPresenter.loadBooksForLanguagePreference();
- verify(bookRepository).getBooksForLanguage(eq("EN"), eq(false), booksForLanguageCallbackArgumentCaptor.capture());
+ verify(bookRepository).getBooksForLanguage(eq("EN"), booksForLanguageCallbackArgumentCaptor.capture());
booksForLanguageCallbackArgumentCaptor.getValue().onBooksLoadError(new Exception("WHOOPS"));
verify(listBookView).showErrorScreen(true, "WHOOPS", true);
diff --git a/build.gradle b/build.gradle
index 1a0d55f..bf9cbd9 100644
--- a/build.gradle
+++ b/build.gradle
@@ -5,7 +5,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:2.0.0-beta7'
+ classpath 'com.android.tools.build:gradle:2.1.0-beta3'
classpath 'com.google.gms:google-services:1.5.0-beta2'
classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.1'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3'
@@ -24,7 +24,7 @@ ext {
// Sdk and tools
// App dependencies
- supportLibraryVersion = '23.2.1'
+ supportLibraryVersion = '23.3.0'
googlePlayServicesVersion = '8.3.0'
guavaVersion = '18.0'
glideVersion = '3.6.1'
diff --git a/circle.yml b/circle.yml
index e77ab07..fdc5df4 100644
--- a/circle.yml
+++ b/circle.yml
@@ -6,10 +6,34 @@ dependencies:
pre:
- touch app/google-services.json
- echo $GOOGLE_SERVICES_JSON > app/google-services.json
+ - android list sdk --extended
- echo y | android update sdk --no-ui --all --filter "tools,platform-tools,android-23"
- - echo y | android update sdk --no-ui --all --filter "build-tools-23.0.2"
+ - echo y | android update sdk --no-ui --all --filter "build-tools-23.0.3"
+ - echo y | android update sdk --no-ui --all --filter "extra-android-m2repository"
test:
+ pre:
+ - android list targets
+ - android create avd -n emulatorwithgoogleapi22 -t 12 --tag google_apis
+ - echo 'vm.heapSize=512' >> ~/.android/avd/emulatorwithgoogleapi22.ini
+ - echo 'hw.ramSize=1024' >> ~/.android/avd/emulatorwithgoogleapi22.ini
+ - cat ~/.android/avd/emulatorwithgoogleapi22.ini
+ - emulator -avd emulatorwithgoogleapi22 -no-audio -no-window :
+ background: true
+ parallel: true
+ - circle-android wait-for-boot
+ - adb shell input keyevent 82
+ - adb shell svc power stayon true
+ - adb shell settings put global window_animation_scale 0
+ - adb shell settings put global transition_animation_scale 0
+ - adb shell settings put global animator_duration_scale 0
+
override:
- - ./gradlew assembleDebug
- - cp -r app/build/outputs $CIRCLE_ARTIFACTS
\ No newline at end of file
+ - ./gradlew createMockDebugCoverageReport
+ - ./gradlew test
+
+ post:
+ - cp -r app/build/outputs $CIRCLE_ARTIFACTS
+ - cp -r app/build/outputs/androidTest-results/ $CIRCLE_TEST_REPORTS
+ - cp -r app/build/reports/coverage/ $CIRCLE_TEST_REPORTS
+ - cp -r app/build/test-results/mockDebug/ $CIRCLE_TEST_REPORTS
diff --git a/fabbutton/build.gradle b/fabbutton/build.gradle
index 1185e8b..5903a88 100644
--- a/fabbutton/build.gradle
+++ b/fabbutton/build.gradle
@@ -34,7 +34,7 @@ def gitUrl = 'https://github.com/ckurtm/FabButton.git'
android {
compileSdkVersion 23
- buildToolsVersion "23.0.2"
+ buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 14
@@ -51,7 +51,7 @@ android {
}
dependencies {
- compile 'com.android.support:design:23.1.1'
+ compile 'com.android.support:design:23.3.0'
}
/*
diff --git a/gradle.properties b/gradle.properties
index e7d8884..0b9a258 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -19,4 +19,4 @@ org.gradle.configureondemand=true
org.gradle.parallel=true
BOOKDASH_PARSE_APP_ID=jmFMwHDkqv60OSbEhapsVrgQnt8HJSETBYIb7bOg
BOOKDASH_PARSE_CLIENT_ID=7ImBEmLBAOoNtk3ypKofy4IJlznEB776algUPaiQ
-systemProp.http.proxyPort=3128
+
diff --git a/set_animation_permissions.sh b/set_animation_permissions.sh
new file mode 100644
index 0000000..75212fc
--- /dev/null
+++ b/set_animation_permissions.sh
@@ -0,0 +1,24 @@
+#!/bin/bash
+#
+# source https://github.com/zielmicha/adb-wrapper
+#
+# argument: apk package
+# Set permission android.permission.SET_ANIMATION_SCALE for each device.
+# ex: sh set_animation_permissions.sh
+#
+
+adb=$ANDROID_HOME/platform-tools/adb
+package=$1
+
+if [ "$#" = 0 ]; then
+ echo "No parameters found, run with sh set_animation_permissions.sh "
+ exit 0
+fi
+
+# get all the devices
+devices=$($adb devices | grep -v 'List of devices' | cut -f1 | grep '.')
+
+for device in $devices; do
+ echo "Setting permissions to device" $device "for package" $package
+ $adb -s $device shell pm grant $package android.permission.SET_ANIMATION_SCALE
+done
\ No newline at end of file