From 41e6205443c20d14a9f49ad9269442d67228747c Mon Sep 17 00:00:00 2001 From: Annyce Davis Date: Sat, 24 Oct 2015 19:49:19 -0400 Subject: [PATCH 1/6] [*] mvp implementation --- app/src/main/AndroidManifest.xml | 2 +- .../adeptandroid/activities/MainActivity.java | 89 ------------------- .../adeptandroid/books/BooksActivity.java | 52 +++++++++++ .../{adapters => books}/BooksAdapter.java | 7 +- .../adeptandroid/books/BooksContract.java | 18 ++++ .../adeptandroid/books/BooksPresenter.java | 62 +++++++++++++ 6 files changed, 139 insertions(+), 91 deletions(-) delete mode 100644 app/src/main/java/info/adavis/adeptandroid/activities/MainActivity.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java rename app/src/main/java/info/adavis/adeptandroid/{adapters => books}/BooksAdapter.java (95%) create mode 100644 app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 8f444ee..4fbf0ac 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -11,7 +11,7 @@ android:label="@string/app_name" android:theme="@style/AppTheme" > diff --git a/app/src/main/java/info/adavis/adeptandroid/activities/MainActivity.java b/app/src/main/java/info/adavis/adeptandroid/activities/MainActivity.java deleted file mode 100644 index ef9657f..0000000 --- a/app/src/main/java/info/adavis/adeptandroid/activities/MainActivity.java +++ /dev/null @@ -1,89 +0,0 @@ -package info.adavis.adeptandroid.activities; - -import android.os.Bundle; -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 com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; -import java.util.List; - -import butterknife.Bind; -import butterknife.ButterKnife; -import info.adavis.adeptandroid.models.Book; -import info.adavis.adeptandroid.R; -import info.adavis.adeptandroid.adapters.BooksAdapter; -import timber.log.Timber; - -public class MainActivity extends AppCompatActivity { - - private static final String CHARSET_NAME = "UTF-8"; - - private List books; - - @Bind(R.id.recyclerView) RecyclerView recyclerView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - ButterKnife.bind(this); - - initDataSet(); - configureLayout(); - } - - private void configureLayout() { - setSupportActionBar((Toolbar) ButterKnife.findById(this, R.id.toolbar)); - - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); - recyclerView.setLayoutManager(layoutManager); - recyclerView.setAdapter(new BooksAdapter(this, books)); - } - - private void initDataSet() { - String json = null; - - try { - json = getJsonData(); - } - catch (Exception e) { - Timber.e("an exception occurred", e); - } - - if (json != null) { - books = new Gson().fromJson(new StringReader(json), new TypeToken>() { }.getType()); - } - } - - private String getJsonData() throws Exception { - Writer writer = new StringWriter(); - InputStream is = null; - try { - is = getResources().openRawResource(R.raw.sample_data); - Reader reader = new BufferedReader(new InputStreamReader(is, CHARSET_NAME)); - int n; - char[] buffer = new char[1024]; - while ((n = reader.read(buffer)) != -1) { - writer.write(buffer, 0, n); - } - } finally { - if (is != null) { - is.close(); - } - } - - return writer.toString(); - } -} diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java new file mode 100644 index 0000000..caaf3cc --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java @@ -0,0 +1,52 @@ +package info.adavis.adeptandroid.books; + +import android.os.Bundle; +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 java.util.ArrayList; +import java.util.List; + +import butterknife.Bind; +import butterknife.ButterKnife; +import info.adavis.adeptandroid.R; +import info.adavis.adeptandroid.models.Book; + +public class BooksActivity extends AppCompatActivity implements BooksContract.View { + + private BooksPresenter booksPresenter; + private BooksAdapter booksAdapter; + + @Bind(R.id.recyclerView) RecyclerView recyclerView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + ButterKnife.bind(this); + + booksPresenter = new BooksPresenter(this); + booksAdapter = new BooksAdapter(this, new ArrayList(0)); + + booksPresenter.initDataSet(getResources().openRawResource(R.raw.sample_data)); + + configureLayout(); + } + + @Override + public void showBooks(List books) { + booksAdapter.updateBooks(books); + } + + private void configureLayout() { + setSupportActionBar((Toolbar) ButterKnife.findById(this, R.id.toolbar)); + + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(booksAdapter); + } + +} diff --git a/app/src/main/java/info/adavis/adeptandroid/adapters/BooksAdapter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java similarity index 95% rename from app/src/main/java/info/adavis/adeptandroid/adapters/BooksAdapter.java rename to app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java index b594257..252839e 100644 --- a/app/src/main/java/info/adavis/adeptandroid/adapters/BooksAdapter.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package info.adavis.adeptandroid.adapters; +package info.adavis.adeptandroid.books; import android.content.Context; import android.support.v7.widget.RecyclerView; @@ -94,4 +94,9 @@ public void onBindViewHolder(ViewHolder viewHolder, final int position) { public int getItemCount() { return books.size(); } + + public void updateBooks(List books) { + this.books = books; + notifyDataSetChanged(); + } } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java new file mode 100644 index 0000000..7cb9c94 --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java @@ -0,0 +1,18 @@ +package info.adavis.adeptandroid.books; + +import java.util.List; + +import info.adavis.adeptandroid.models.Book; + +/** + * The contract between the view and presenter + */ +public interface BooksContract { + + interface View { + + void showBooks(List books); + + } + +} diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java new file mode 100644 index 0000000..8519397 --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java @@ -0,0 +1,62 @@ +package info.adavis.adeptandroid.books; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.BufferedReader; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.List; + +import info.adavis.adeptandroid.models.Book; +import timber.log.Timber; + +public class BooksPresenter { + + public static final String CHARSET_NAME = "UTF-8"; + + private final BooksContract.View booksView; + + public BooksPresenter(BooksContract.View booksView) { + this.booksView = booksView; + } + + public void initDataSet(InputStream is) { + String json = null; + + try { + json = getJsonData(is); + } catch (Exception e) { + Timber.e("an exception occurred", e); + } + + if (json != null) { + List books = new Gson().fromJson(new StringReader(json), new TypeToken>() { + }.getType()); + + booksView.showBooks(books); + } + } + + private String getJsonData(InputStream is) throws Exception { + Writer writer = new StringWriter(); + try { + Reader reader = new BufferedReader(new InputStreamReader(is, CHARSET_NAME)); + int n; + char[] buffer = new char[1024]; + while ((n = reader.read(buffer)) != -1) { + writer.write(buffer, 0, n); + } + } finally { + if (is != null) { + is.close(); + } + } + + return writer.toString(); + } +} \ No newline at end of file From aeb8452a14b54414e658c537f99d2dc6f67b312e Mon Sep 17 00:00:00 2001 From: Annyce Davis Date: Sun, 17 Apr 2016 18:28:47 -0400 Subject: [PATCH 2/6] [+] Adding Support for Retrofit2 * Removed unused unit tests * Switched from using local JSON to Remote API * Created Injector class for handling dependencies * Upgraded some lib dependencies --- app/build.gradle | 36 ++++++--- .../adavis/adeptandroid/ApplicationTest.java | 13 ---- .../info/adavis/adeptandroid/Constants.java | 9 +++ .../adeptandroid/books/BookService.java | 16 ++++ .../adeptandroid/books/BooksActivity.java | 45 +++++++---- .../adeptandroid/books/BooksContract.java | 9 ++- .../adeptandroid/books/BooksPresenter.java | 75 +++++++------------ .../info/adavis/adeptandroid/di/Injector.java | 26 +++++++ app/src/main/res/values/strings.xml | 1 + .../adavis/adeptandroid/ExampleUnitTest.java | 15 ---- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 4 +- 12 files changed, 146 insertions(+), 105 deletions(-) delete mode 100644 app/src/androidTest/java/info/adavis/adeptandroid/ApplicationTest.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/Constants.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/books/BookService.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/di/Injector.java delete mode 100644 app/src/test/java/info/adavis/adeptandroid/ExampleUnitTest.java diff --git a/app/build.gradle b/app/build.gradle index b1ac16f..87bfb8c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,7 +2,7 @@ apply plugin: 'com.android.application' android { compileSdkVersion 23 - buildToolsVersion "23.0.1" + buildToolsVersion "23.0.2" defaultConfig { applicationId "info.adavis.adeptandroid" @@ -17,25 +17,43 @@ android { proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + lintOptions { + abortOnError false + } } ext { - supportLibraryVersion = '23.0.1' - okhttpVersion = '2.4.0' + supportLibraryVersion = '23.3.0' + retrofitVersion = '2.0.0' } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' + // Support Libraries compile "com.android.support:appcompat-v7:$supportLibraryVersion" compile "com.android.support:recyclerview-v7:$supportLibraryVersion" compile "com.android.support:design:$supportLibraryVersion" - compile "com.squareup.okhttp:okhttp:$okhttpVersion" - compile "com.squareup.okhttp:okhttp-urlconnection:$okhttpVersion" + + // REST Interactions + compile ("com.squareup.retrofit2:retrofit:$retrofitVersion") { + exclude module: 'okhttp' + } + + // JSON Parsing + compile 'com.google.code.gson:gson:2.4' + compile "com.squareup.retrofit2:converter-gson:$retrofitVersion" + + // View Injection compile 'com.jakewharton:butterknife:7.0.1' + + // Logging compile 'com.jakewharton.timber:timber:3.1.0' + + // Events compile 'de.greenrobot:eventbus:2.4.0' - compile 'com.mcxiaoke.volley:library:1.0.18' + + // Image Loading compile 'com.squareup.picasso:picasso:2.5.2' - compile 'org.immutables:gson:2.1.0.alpha' + + // Testing + testCompile 'junit:junit:4.12' } diff --git a/app/src/androidTest/java/info/adavis/adeptandroid/ApplicationTest.java b/app/src/androidTest/java/info/adavis/adeptandroid/ApplicationTest.java deleted file mode 100644 index f31ce30..0000000 --- a/app/src/androidTest/java/info/adavis/adeptandroid/ApplicationTest.java +++ /dev/null @@ -1,13 +0,0 @@ -package info.adavis.adeptandroid; - -import android.app.Application; -import android.test.ApplicationTestCase; - -/** - * Testing Fundamentals - */ -public class ApplicationTest extends ApplicationTestCase { - public ApplicationTest() { - super(Application.class); - } -} \ No newline at end of file diff --git a/app/src/main/java/info/adavis/adeptandroid/Constants.java b/app/src/main/java/info/adavis/adeptandroid/Constants.java new file mode 100644 index 0000000..77a13ef --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/Constants.java @@ -0,0 +1,9 @@ +package info.adavis.adeptandroid; + +/** + * @author Annyce Davis + */ +public class Constants +{ + public static final String BASE_URL = ""; +} diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BookService.java b/app/src/main/java/info/adavis/adeptandroid/books/BookService.java new file mode 100644 index 0000000..fdc2b47 --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/books/BookService.java @@ -0,0 +1,16 @@ +package info.adavis.adeptandroid.books; + +import java.util.List; + +import info.adavis.adeptandroid.models.Book; +import retrofit2.Call; +import retrofit2.http.GET; + +/** + * @author Annyce Davis + */ +public interface BookService +{ + @GET( "api/books" ) + Call> getBooks(); +} diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java index caaf3cc..9a1fa0f 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java @@ -5,6 +5,7 @@ import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.Toolbar; +import android.widget.Toast; import java.util.ArrayList; import java.util.List; @@ -12,41 +13,53 @@ import butterknife.Bind; import butterknife.ButterKnife; import info.adavis.adeptandroid.R; +import info.adavis.adeptandroid.di.Injector; import info.adavis.adeptandroid.models.Book; -public class BooksActivity extends AppCompatActivity implements BooksContract.View { +public class BooksActivity extends AppCompatActivity implements BooksContract.View +{ private BooksPresenter booksPresenter; private BooksAdapter booksAdapter; - @Bind(R.id.recyclerView) RecyclerView recyclerView; + @Bind(R.id.recyclerView) + RecyclerView recyclerView; @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); + protected void onCreate (Bundle savedInstanceState) + { + super.onCreate( savedInstanceState ); + setContentView( R.layout.activity_main ); - ButterKnife.bind(this); + ButterKnife.bind( this ); - booksPresenter = new BooksPresenter(this); - booksAdapter = new BooksAdapter(this, new ArrayList(0)); + booksPresenter = new BooksPresenter( this, Injector.provideBookService() ); + booksAdapter = new BooksAdapter( this, new ArrayList( 0 ) ); - booksPresenter.initDataSet(getResources().openRawResource(R.raw.sample_data)); + booksPresenter.initDataSet(); configureLayout(); } @Override - public void showBooks(List books) { - booksAdapter.updateBooks(books); + public void showBooks (List books) + { + booksAdapter.updateBooks( books ); } - private void configureLayout() { - setSupportActionBar((Toolbar) ButterKnife.findById(this, R.id.toolbar)); + @Override + public void showErrorMessage () + { + Toast.makeText( this, R.string.books_loading_unsuccessful, Toast.LENGTH_SHORT).show(); + } + + private void configureLayout () + { + setSupportActionBar( (Toolbar) ButterKnife.findById( this, R.id.toolbar ) ); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); - recyclerView.setLayoutManager(layoutManager); - recyclerView.setAdapter(booksAdapter); + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager( this ); + recyclerView.setLayoutManager( layoutManager ); + recyclerView.setAdapter( booksAdapter ); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java index 7cb9c94..abb3dbe 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java @@ -7,12 +7,15 @@ /** * The contract between the view and presenter */ -public interface BooksContract { +public interface BooksContract +{ - interface View { + interface View + { - void showBooks(List books); + void showBooks (List books); + void showErrorMessage (); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java index 8519397..2fbf0ac 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java @@ -1,62 +1,45 @@ package info.adavis.adeptandroid.books; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; - -import java.io.BufferedReader; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.io.StringReader; -import java.io.StringWriter; -import java.io.Writer; import java.util.List; import info.adavis.adeptandroid.models.Book; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; import timber.log.Timber; -public class BooksPresenter { - - public static final String CHARSET_NAME = "UTF-8"; - +public class BooksPresenter +{ private final BooksContract.View booksView; + private final BookService service; - public BooksPresenter(BooksContract.View booksView) { + public BooksPresenter (BooksContract.View booksView, BookService service) + { this.booksView = booksView; + this.service = service; } - public void initDataSet(InputStream is) { - String json = null; - - try { - json = getJsonData(is); - } catch (Exception e) { - Timber.e("an exception occurred", e); - } - - if (json != null) { - List books = new Gson().fromJson(new StringReader(json), new TypeToken>() { - }.getType()); - - booksView.showBooks(books); - } - } - - private String getJsonData(InputStream is) throws Exception { - Writer writer = new StringWriter(); - try { - Reader reader = new BufferedReader(new InputStreamReader(is, CHARSET_NAME)); - int n; - char[] buffer = new char[1024]; - while ((n = reader.read(buffer)) != -1) { - writer.write(buffer, 0, n); - } - } finally { - if (is != null) { - is.close(); + public void initDataSet () + { + service.getBooks().enqueue( new Callback>() + { + @Override + public void onResponse (Call> call, Response> response) + { + if ( response.isSuccessful() ) + { + booksView.showBooks( response.body() ); + Timber.i( "Books data was loaded from API." ); + } } - } - return writer.toString(); + @Override + public void onFailure (Call> call, Throwable t) + { + booksView.showErrorMessage(); + Timber.e( t, "Unable to load the books data from API." ); + } + } ); } + } \ No newline at end of file diff --git a/app/src/main/java/info/adavis/adeptandroid/di/Injector.java b/app/src/main/java/info/adavis/adeptandroid/di/Injector.java new file mode 100644 index 0000000..eb815e5 --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/di/Injector.java @@ -0,0 +1,26 @@ +package info.adavis.adeptandroid.di; + +import info.adavis.adeptandroid.Constants; +import info.adavis.adeptandroid.books.BookService; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +/** + * @author Annyce Davis + */ +public class Injector +{ + public static Retrofit provideRetrofit (String baseUrl) + { + return new Retrofit.Builder() + .baseUrl( baseUrl ) + .addConverterFactory( GsonConverterFactory.create() ) + .build(); + } + + public static BookService provideBookService () + { + return provideRetrofit( Constants.BASE_URL ).create( BookService.class ); + } + +} diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 46bf308..dbc6c3b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2,4 +2,5 @@ Adept Android thumbnail %d pages + Unable to load the books. diff --git a/app/src/test/java/info/adavis/adeptandroid/ExampleUnitTest.java b/app/src/test/java/info/adavis/adeptandroid/ExampleUnitTest.java deleted file mode 100644 index c5dafff..0000000 --- a/app/src/test/java/info/adavis/adeptandroid/ExampleUnitTest.java +++ /dev/null @@ -1,15 +0,0 @@ -package info.adavis.adeptandroid; - -import org.junit.Test; - -import static org.junit.Assert.*; - -/** - * To work on unit tests, switch the Test Artifact in the Build Variants view. - */ -public class ExampleUnitTest { - @Test - public void addition_isCorrect() throws Exception { - assertEquals(4, 2 + 2); - } -} \ No newline at end of file diff --git a/build.gradle b/build.gradle index be515a8..168f129 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:1.3.0' + classpath 'com.android.tools.build:gradle:2.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9d079bb..9c5eb69 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Wed Sep 23 12:38:38 EDT 2015 +#Sun Apr 17 17:50:31 EDT 2016 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.4-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-all.zip From 35bfcf196c8bfe0cd781d5039e27b3612f7d8700 Mon Sep 17 00:00:00 2001 From: Annyce Davis Date: Sun, 17 Apr 2016 22:20:10 -0400 Subject: [PATCH 3/6] [*] Updated the API Endpoint --- app/src/main/java/info/adavis/adeptandroid/Constants.java | 2 +- .../main/java/info/adavis/adeptandroid/books/BookService.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/info/adavis/adeptandroid/Constants.java b/app/src/main/java/info/adavis/adeptandroid/Constants.java index 77a13ef..5523ffa 100644 --- a/app/src/main/java/info/adavis/adeptandroid/Constants.java +++ b/app/src/main/java/info/adavis/adeptandroid/Constants.java @@ -5,5 +5,5 @@ */ public class Constants { - public static final String BASE_URL = ""; + public static final String BASE_URL = "http://10.0.2.2:8080"; } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BookService.java b/app/src/main/java/info/adavis/adeptandroid/books/BookService.java index fdc2b47..08748d3 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BookService.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BookService.java @@ -11,6 +11,6 @@ */ public interface BookService { - @GET( "api/books" ) + @GET( "books" ) Call> getBooks(); } From 9ac140a3b01378582ff5f2b53288dc3c0905613d Mon Sep 17 00:00:00 2001 From: Annyce Davis Date: Mon, 18 Apr 2016 17:42:06 -0400 Subject: [PATCH 4/6] [*] Upgraded a few lib dependencies --- app/build.gradle | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 87bfb8c..c4f3d41 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,7 +24,7 @@ android { ext { supportLibraryVersion = '23.3.0' - retrofitVersion = '2.0.0' + retrofitVersion = '2.0.2' } dependencies { @@ -34,12 +34,10 @@ dependencies { compile "com.android.support:design:$supportLibraryVersion" // REST Interactions - compile ("com.squareup.retrofit2:retrofit:$retrofitVersion") { - exclude module: 'okhttp' - } + compile ("com.squareup.retrofit2:retrofit:$retrofitVersion") // JSON Parsing - compile 'com.google.code.gson:gson:2.4' + compile 'com.google.code.gson:gson:2.6.1' compile "com.squareup.retrofit2:converter-gson:$retrofitVersion" // View Injection From a6153e6d0c7942fb81a1b0aea314bb3fa2056bf4 Mon Sep 17 00:00:00 2001 From: Annyce Davis Date: Fri, 29 Apr 2016 20:32:15 -0400 Subject: [PATCH 5/6] [+] Adds Support For Additional GET Calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Created a new activity to display a single book’s info * Updated the BooksActivity to have a callback for when a book was clicked in the list * Created a callback interface in the BooksAdapter * Added 2 additional GET requests to the BookService * Added the id field to the Book class * Upgraded to 2.1.0 of the Android Gradle Plugin --- app/src/main/AndroidManifest.xml | 7 +++ .../adeptandroid/book/BookActivity.java | 57 +++++++++++++++++++ .../adeptandroid/book/BookContract.java | 17 ++++++ .../adeptandroid/book/BookPresenter.java | 44 ++++++++++++++ .../adeptandroid/books/BookService.java | 16 ------ .../adeptandroid/books/BooksActivity.java | 23 +++++++- .../adeptandroid/books/BooksAdapter.java | 32 +++++++++-- .../adeptandroid/books/BooksPresenter.java | 1 + .../adavis/adeptandroid/data/BookService.java | 24 ++++++++ .../info/adavis/adeptandroid/di/Injector.java | 2 +- .../info/adavis/adeptandroid/models/Book.java | 5 ++ app/src/main/res/layout/activity_book.xml | 54 ++++++++++++++++++ app/src/main/res/layout/activity_main.xml | 20 +------ app/src/main/res/layout/content_main.xml | 2 +- app/src/main/res/layout/toolbar.xml | 19 +++++++ app/src/main/res/values/dimens.xml | 1 + app/src/main/res/values/strings.xml | 7 +++ build.gradle | 2 +- 18 files changed, 288 insertions(+), 45 deletions(-) create mode 100644 app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/book/BookContract.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java delete mode 100644 app/src/main/java/info/adavis/adeptandroid/books/BookService.java create mode 100644 app/src/main/java/info/adavis/adeptandroid/data/BookService.java create mode 100644 app/src/main/res/layout/activity_book.xml create mode 100644 app/src/main/res/layout/toolbar.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4fbf0ac..89a0ef1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -10,6 +10,7 @@ android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > + + + + + diff --git a/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java b/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java new file mode 100644 index 0000000..b980d19 --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java @@ -0,0 +1,57 @@ +package info.adavis.adeptandroid.book; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.widget.TextView; +import android.widget.Toast; + +import butterknife.Bind; +import butterknife.ButterKnife; +import info.adavis.adeptandroid.R; +import info.adavis.adeptandroid.di.Injector; +import info.adavis.adeptandroid.models.Book; + +public class BookActivity extends AppCompatActivity implements BookContract.View +{ + public static final String EXTRA_BOOK_ID = "EXTRA_BOOK_ID"; + + @Bind( R.id.titleText ) + TextView titleText; + + @Bind( R.id.authorText ) + TextView authorText; + + @Override + protected void onCreate (Bundle savedInstanceState) + { + super.onCreate( savedInstanceState ); + setContentView( R.layout.activity_book ); + + ButterKnife.bind( this ); + + BookPresenter bookPresenter = new BookPresenter( this, Injector.provideBookService() ); + bookPresenter.retrieveBook(getIntent().getLongExtra(EXTRA_BOOK_ID, 1)); + + configureLayout(); + } + + @Override + public void showBook (Book book) + { + titleText.setText( book.getTitle() ); + authorText.setText( book.getAuthor() ); + } + + @Override + public void showErrorMessage () + { + Toast.makeText( this, R.string.book_loading_unsuccessful, Toast.LENGTH_SHORT).show(); + } + + private void configureLayout () + { + setSupportActionBar( (Toolbar) ButterKnife.findById( this, R.id.toolbar ) ); + } + +} diff --git a/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java b/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java new file mode 100644 index 0000000..729bd38 --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java @@ -0,0 +1,17 @@ +package info.adavis.adeptandroid.book; + +import info.adavis.adeptandroid.models.Book; + +/** + * The contract between the view and presenter + */ +public interface BookContract +{ + interface View + { + void showErrorMessage (); + + void showBook (Book book); + } + +} diff --git a/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java b/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java new file mode 100644 index 0000000..8cfa9cf --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java @@ -0,0 +1,44 @@ +package info.adavis.adeptandroid.book; + +import info.adavis.adeptandroid.data.BookService; +import info.adavis.adeptandroid.models.Book; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import timber.log.Timber; + +public class BookPresenter +{ + private final BookContract.View bookView; + private final BookService service; + + public BookPresenter (BookContract.View bookView, BookService service) + { + this.bookView = bookView; + this.service = service; + } + + public void retrieveBook (long id) + { + service.getBook( id ).enqueue( new Callback() + { + @Override + public void onResponse (Call call, Response response) + { + if ( response.isSuccessful() ) + { + bookView.showBook( response.body() ); + Timber.i( "Book data was loaded from API." ); + } + } + + @Override + public void onFailure (Call call, Throwable t) + { + bookView.showErrorMessage(); + Timber.e( t, "Unable to load the book data from API." ); + } + } ); + } + +} \ No newline at end of file diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BookService.java b/app/src/main/java/info/adavis/adeptandroid/books/BookService.java deleted file mode 100644 index 08748d3..0000000 --- a/app/src/main/java/info/adavis/adeptandroid/books/BookService.java +++ /dev/null @@ -1,16 +0,0 @@ -package info.adavis.adeptandroid.books; - -import java.util.List; - -import info.adavis.adeptandroid.models.Book; -import retrofit2.Call; -import retrofit2.http.GET; - -/** - * @author Annyce Davis - */ -public interface BookService -{ - @GET( "books" ) - Call> getBooks(); -} diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java index 9a1fa0f..3fb19dc 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java @@ -1,5 +1,7 @@ package info.adavis.adeptandroid.books; +import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.LinearLayoutManager; @@ -13,13 +15,14 @@ import butterknife.Bind; import butterknife.ButterKnife; import info.adavis.adeptandroid.R; +import info.adavis.adeptandroid.book.BookActivity; import info.adavis.adeptandroid.di.Injector; import info.adavis.adeptandroid.models.Book; +import timber.log.Timber; public class BooksActivity extends AppCompatActivity implements BooksContract.View { - private BooksPresenter booksPresenter; private BooksAdapter booksAdapter; @Bind(R.id.recyclerView) @@ -33,8 +36,8 @@ protected void onCreate (Bundle savedInstanceState) ButterKnife.bind( this ); - booksPresenter = new BooksPresenter( this, Injector.provideBookService() ); - booksAdapter = new BooksAdapter( this, new ArrayList( 0 ) ); + BooksPresenter booksPresenter = new BooksPresenter( this, Injector.provideBookService() ); + booksAdapter = new BooksAdapter( this, new ArrayList( 0 ), itemListener ); booksPresenter.initDataSet(); @@ -60,6 +63,20 @@ private void configureLayout () RecyclerView.LayoutManager layoutManager = new LinearLayoutManager( this ); recyclerView.setLayoutManager( layoutManager ); recyclerView.setAdapter( booksAdapter ); + recyclerView.setHasFixedSize( true ); } + private BooksAdapter.BookItemListener itemListener = new BooksAdapter.BookItemListener() + { + + @Override + public void onBookClick (long id) + { + Timber.d( "book clicked id: %d", id ); + Intent intent = new Intent( BooksActivity.this, BookActivity.class ); + intent.putExtra( BookActivity.EXTRA_BOOK_ID, id ); + startActivity(intent); + } + }; + } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java index 252839e..3df8871 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java @@ -31,16 +31,17 @@ import butterknife.Bind; import butterknife.ButterKnife; -import info.adavis.adeptandroid.models.Book; import info.adavis.adeptandroid.R; +import info.adavis.adeptandroid.models.Book; import timber.log.Timber; public class BooksAdapter extends RecyclerView.Adapter { private WeakReference context; private List books; + private BookItemListener itemListener; - public static class ViewHolder extends RecyclerView.ViewHolder { + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { @Bind(R.id.titleTextView) TextView titleTextView; @Bind(R.id.authorTextView) TextView authorTextView; @@ -48,15 +49,28 @@ public static class ViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.pagesTextView) TextView pagesTextView; @Bind(R.id.imageView) ImageView imageView; - public ViewHolder(View v) { + BookItemListener itemListener; + + public ViewHolder(View v, BookItemListener itemListener) { super(v); ButterKnife.bind(this, v); + + this.itemListener = itemListener; + v.setOnClickListener(this); + } + + @Override + public void onClick (View v) + { + Book book = getItem(getAdapterPosition()); + this.itemListener.onBookClick( book.getId() ); } } - public BooksAdapter(Context context, List books) { + public BooksAdapter (Context context, List books, BookItemListener itemListener) { this.context = new WeakReference<>(context); this.books = books; + this.itemListener = itemListener; } @Override @@ -64,7 +78,7 @@ public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { View v = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.book_row_item, viewGroup, false); - return new ViewHolder(v); + return new ViewHolder(v, this.itemListener); } @Override @@ -99,4 +113,12 @@ public void updateBooks(List books) { this.books = books; notifyDataSetChanged(); } + + private Book getItem(int adapterPosition) { + return books.get(adapterPosition); + } + + public interface BookItemListener { + void onBookClick(long id); + } } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java index 2fbf0ac..8a8fec0 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java @@ -2,6 +2,7 @@ import java.util.List; +import info.adavis.adeptandroid.data.BookService; import info.adavis.adeptandroid.models.Book; import retrofit2.Call; import retrofit2.Callback; diff --git a/app/src/main/java/info/adavis/adeptandroid/data/BookService.java b/app/src/main/java/info/adavis/adeptandroid/data/BookService.java new file mode 100644 index 0000000..a6ee0bb --- /dev/null +++ b/app/src/main/java/info/adavis/adeptandroid/data/BookService.java @@ -0,0 +1,24 @@ +package info.adavis.adeptandroid.data; + +import java.util.List; + +import info.adavis.adeptandroid.models.Book; +import retrofit2.Call; +import retrofit2.http.GET; +import retrofit2.http.Path; +import retrofit2.http.Query; + +/** + * @author Annyce Davis + */ +public interface BookService +{ + @GET( "books" ) + Call> getBooks(); + + @GET( "books" ) + Call> search( @Query( "q" ) String query ); + + @GET( "books/{id}" ) + Call getBook( @Path( "id" ) Long id ); +} diff --git a/app/src/main/java/info/adavis/adeptandroid/di/Injector.java b/app/src/main/java/info/adavis/adeptandroid/di/Injector.java index eb815e5..e174043 100644 --- a/app/src/main/java/info/adavis/adeptandroid/di/Injector.java +++ b/app/src/main/java/info/adavis/adeptandroid/di/Injector.java @@ -1,7 +1,7 @@ package info.adavis.adeptandroid.di; import info.adavis.adeptandroid.Constants; -import info.adavis.adeptandroid.books.BookService; +import info.adavis.adeptandroid.data.BookService; import retrofit2.Retrofit; import retrofit2.converter.gson.GsonConverterFactory; diff --git a/app/src/main/java/info/adavis/adeptandroid/models/Book.java b/app/src/main/java/info/adavis/adeptandroid/models/Book.java index cb64c89..b63c4b9 100644 --- a/app/src/main/java/info/adavis/adeptandroid/models/Book.java +++ b/app/src/main/java/info/adavis/adeptandroid/models/Book.java @@ -3,6 +3,7 @@ public class Book { + long id; String title; String author; String bookUrl; @@ -10,6 +11,10 @@ public class Book { String displayDate; int numberOfPages; + public long getId() { + return id; + } + public String getTitle() { return title; } diff --git a/app/src/main/res/layout/activity_book.xml b/app/src/main/res/layout/activity_book.xml new file mode 100644 index 0000000..19bdbff --- /dev/null +++ b/app/src/main/res/layout/activity_book.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7b1bb4e..a9e8da2 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -1,27 +1,11 @@ + android:fitsSystemWindows="true"> - - - - - + diff --git a/app/src/main/res/layout/content_main.xml b/app/src/main/res/layout/content_main.xml index a8b39be..98a3279 100644 --- a/app/src/main/res/layout/content_main.xml +++ b/app/src/main/res/layout/content_main.xml @@ -12,7 +12,7 @@ android:background="@color/indigo_100" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:showIn="@layout/activity_main" - tools:context=".MainActivity"> + tools:context=".books.BooksActivity"> + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index be8f6e1..759aee7 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,4 +8,5 @@ 4dp 80dp 108dp + 16dp diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index dbc6c3b..cb8cd8b 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -3,4 +3,11 @@ thumbnail %d pages Unable to load the books. + Unable to load the book + Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ut enim et augue interdum pellentesque. + Maecenas elementum nibh nulla, sit amet egestas dui tristique efficitur. Sed vitae feugiat magna. Nunc sed eros nulla. + In molestie et neque fringilla egestas. Ut elementum scelerisque ligula in pulvinar.\n\nUt in neque at + leo rutrum vestibulum ac vel lectus. Duis in lobortis erat, a rhoncus mauris. + Curabitur a aliquet massa. Quisque aliquam mauris id molestie egestas. + Vivamus vitae massa cursus, aliquam urna sit amet, placerat nibh. diff --git a/build.gradle b/build.gradle index 168f129..03bced9 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ buildscript { jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.0.0' + classpath 'com.android.tools.build:gradle:2.1.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files From 16fc47f9831a363da78fc9948fafea67e45c3e3e Mon Sep 17 00:00:00 2001 From: Annyce Davis Date: Wed, 29 May 2019 20:39:27 +0200 Subject: [PATCH 6/6] Updated: Project can build again, targeting API 28 --- app/build.gradle | 42 ++++++++------ .../adeptandroid/book/BookActivity.java | 35 +++++------- .../adeptandroid/book/BookContract.java | 4 +- .../adeptandroid/book/BookPresenter.java | 20 +++---- .../adeptandroid/books/BooksActivity.java | 55 ++++++++----------- .../adeptandroid/books/BooksAdapter.java | 47 ++++++++++------ .../adeptandroid/books/BooksContract.java | 4 +- .../adeptandroid/books/BooksPresenter.java | 22 ++++---- .../adavis/adeptandroid/data/BookService.java | 11 ++-- .../info/adavis/adeptandroid/di/Injector.java | 11 ++-- .../info/adavis/adeptandroid/models/Book.java | 2 + build.gradle | 6 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 13 files changed, 138 insertions(+), 123 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index c4f3d41..3d1d625 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,57 +1,65 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion "23.0.2" + compileSdkVersion 28 + buildToolsVersion = '28.0.3' defaultConfig { applicationId "info.adavis.adeptandroid" - minSdkVersion 15 - targetSdkVersion 23 + minSdkVersion 21 + targetSdkVersion 28 versionCode 1 versionName "1.0" } + buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } + lintOptions { abortOnError false } + + compileOptions { + sourceCompatibility = '1.8' + targetCompatibility = '1.8' + } } ext { - supportLibraryVersion = '23.3.0' - retrofitVersion = '2.0.2' + supportLibraryVersion = '28.0.0' + retrofitVersion = '2.5.0' } dependencies { // Support Libraries - compile "com.android.support:appcompat-v7:$supportLibraryVersion" - compile "com.android.support:recyclerview-v7:$supportLibraryVersion" - compile "com.android.support:design:$supportLibraryVersion" + implementation "com.android.support:appcompat-v7:$supportLibraryVersion" + implementation "com.android.support:recyclerview-v7:$supportLibraryVersion" + implementation "com.android.support:design:$supportLibraryVersion" // REST Interactions - compile ("com.squareup.retrofit2:retrofit:$retrofitVersion") + implementation ("com.squareup.retrofit2:retrofit:$retrofitVersion") // JSON Parsing - compile 'com.google.code.gson:gson:2.6.1' - compile "com.squareup.retrofit2:converter-gson:$retrofitVersion" + implementation 'com.google.code.gson:gson:2.8.5' + implementation "com.squareup.retrofit2:converter-gson:$retrofitVersion" // View Injection - compile 'com.jakewharton:butterknife:7.0.1' + implementation 'com.jakewharton:butterknife:9.0.0' + annotationProcessor 'com.jakewharton:butterknife-compiler:9.0.0' // Logging - compile 'com.jakewharton.timber:timber:3.1.0' + implementation 'com.jakewharton.timber:timber:4.7.1' // Events - compile 'de.greenrobot:eventbus:2.4.0' + implementation 'de.greenrobot:eventbus:2.4.0' // Image Loading - compile 'com.squareup.picasso:picasso:2.5.2' + implementation 'com.squareup.picasso:picasso:2.71828@aar' // Testing - testCompile 'junit:junit:4.12' + testImplementation 'junit:junit:4.12' } diff --git a/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java b/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java index b980d19..39d5278 100644 --- a/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java +++ b/app/src/main/java/info/adavis/adeptandroid/book/BookActivity.java @@ -2,11 +2,10 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; import android.widget.TextView; import android.widget.Toast; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import info.adavis.adeptandroid.R; import info.adavis.adeptandroid.di.Injector; @@ -16,42 +15,38 @@ public class BookActivity extends AppCompatActivity implements BookContract.View { public static final String EXTRA_BOOK_ID = "EXTRA_BOOK_ID"; - @Bind( R.id.titleText ) - TextView titleText; - - @Bind( R.id.authorText ) - TextView authorText; + @BindView(R.id.titleText) TextView titleText; + @BindView(R.id.authorText) TextView authorText; @Override - protected void onCreate (Bundle savedInstanceState) + protected void onCreate(Bundle savedInstanceState) { - super.onCreate( savedInstanceState ); - setContentView( R.layout.activity_book ); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_book); - ButterKnife.bind( this ); + ButterKnife.bind(this); - BookPresenter bookPresenter = new BookPresenter( this, Injector.provideBookService() ); + BookPresenter bookPresenter = new BookPresenter(this, Injector.provideBookService()); bookPresenter.retrieveBook(getIntent().getLongExtra(EXTRA_BOOK_ID, 1)); configureLayout(); } @Override - public void showBook (Book book) + public void showBook(Book book) { - titleText.setText( book.getTitle() ); - authorText.setText( book.getAuthor() ); + titleText.setText(book.getTitle()); + authorText.setText(book.getAuthor()); } @Override - public void showErrorMessage () + public void showErrorMessage() { - Toast.makeText( this, R.string.book_loading_unsuccessful, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.book_loading_unsuccessful, Toast.LENGTH_SHORT).show(); } - private void configureLayout () - { - setSupportActionBar( (Toolbar) ButterKnife.findById( this, R.id.toolbar ) ); + private void configureLayout() { + setSupportActionBar(findViewById(R.id.toolbar)); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java b/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java index 729bd38..95822e6 100644 --- a/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java +++ b/app/src/main/java/info/adavis/adeptandroid/book/BookContract.java @@ -9,9 +9,9 @@ public interface BookContract { interface View { - void showErrorMessage (); + void showErrorMessage(); - void showBook (Book book); + void showBook(Book book); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java b/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java index 8cfa9cf..ed98322 100644 --- a/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java +++ b/app/src/main/java/info/adavis/adeptandroid/book/BookPresenter.java @@ -7,38 +7,38 @@ import retrofit2.Response; import timber.log.Timber; -public class BookPresenter +class BookPresenter { private final BookContract.View bookView; private final BookService service; - public BookPresenter (BookContract.View bookView, BookService service) + BookPresenter (BookContract.View bookView, BookService service) { this.bookView = bookView; this.service = service; } - public void retrieveBook (long id) + void retrieveBook (long id) { - service.getBook( id ).enqueue( new Callback() + service.getBook(id).enqueue(new Callback() { @Override public void onResponse (Call call, Response response) { - if ( response.isSuccessful() ) + if (response.isSuccessful()) { - bookView.showBook( response.body() ); - Timber.i( "Book data was loaded from API." ); + bookView.showBook(response.body()); + Timber.i("Book data was loaded from API."); } } @Override - public void onFailure (Call call, Throwable t) + public void onFailure(Call call, Throwable t) { bookView.showErrorMessage(); - Timber.e( t, "Unable to load the book data from API." ); + Timber.e(t, "Unable to load the book data from API."); } - } ); + }); } } \ No newline at end of file diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java index 3fb19dc..48e5526 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksActivity.java @@ -1,18 +1,16 @@ package info.adavis.adeptandroid.books; import android.content.Intent; -import android.net.Uri; import android.os.Bundle; 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.widget.Toast; import java.util.ArrayList; import java.util.List; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import info.adavis.adeptandroid.R; import info.adavis.adeptandroid.book.BookActivity; @@ -25,19 +23,18 @@ public class BooksActivity extends AppCompatActivity implements BooksContract.Vi private BooksAdapter booksAdapter; - @Bind(R.id.recyclerView) - RecyclerView recyclerView; + @BindView(R.id.recyclerView) RecyclerView recyclerView; @Override - protected void onCreate (Bundle savedInstanceState) + protected void onCreate(Bundle savedInstanceState) { - super.onCreate( savedInstanceState ); - setContentView( R.layout.activity_main ); + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); - ButterKnife.bind( this ); + ButterKnife.bind(this); - BooksPresenter booksPresenter = new BooksPresenter( this, Injector.provideBookService() ); - booksAdapter = new BooksAdapter( this, new ArrayList( 0 ), itemListener ); + BooksPresenter booksPresenter = new BooksPresenter(this, Injector.provideBookService()); + booksAdapter = new BooksAdapter(this, new ArrayList<>(0), itemListener); booksPresenter.initDataSet(); @@ -45,38 +42,32 @@ protected void onCreate (Bundle savedInstanceState) } @Override - public void showBooks (List books) + public void showBooks(List books) { - booksAdapter.updateBooks( books ); + booksAdapter.updateBooks(books); } @Override - public void showErrorMessage () + public void showErrorMessage() { - Toast.makeText( this, R.string.books_loading_unsuccessful, Toast.LENGTH_SHORT).show(); + Toast.makeText(this, R.string.books_loading_unsuccessful, Toast.LENGTH_SHORT).show(); } - private void configureLayout () + private void configureLayout() { - setSupportActionBar( (Toolbar) ButterKnife.findById( this, R.id.toolbar ) ); + setSupportActionBar(findViewById(R.id.toolbar)); - RecyclerView.LayoutManager layoutManager = new LinearLayoutManager( this ); - recyclerView.setLayoutManager( layoutManager ); - recyclerView.setAdapter( booksAdapter ); - recyclerView.setHasFixedSize( true ); + RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); + recyclerView.setLayoutManager(layoutManager); + recyclerView.setAdapter(booksAdapter); + recyclerView.setHasFixedSize(true); } - private BooksAdapter.BookItemListener itemListener = new BooksAdapter.BookItemListener() - { - - @Override - public void onBookClick (long id) - { - Timber.d( "book clicked id: %d", id ); - Intent intent = new Intent( BooksActivity.this, BookActivity.class ); - intent.putExtra( BookActivity.EXTRA_BOOK_ID, id ); - startActivity(intent); - } + private BooksAdapter.BookItemListener itemListener = id -> { + Timber.d("book clicked id: %d", id); + Intent intent = new Intent(BooksActivity.this, BookActivity.class); + intent.putExtra(BookActivity.EXTRA_BOOK_ID, id); + startActivity(intent); }; } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java index 3df8871..c71c277 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksAdapter.java @@ -26,32 +26,37 @@ import com.squareup.picasso.Picasso; +import org.jetbrains.annotations.NotNull; + import java.lang.ref.WeakReference; import java.util.List; -import butterknife.Bind; +import butterknife.BindView; import butterknife.ButterKnife; import info.adavis.adeptandroid.R; import info.adavis.adeptandroid.models.Book; import timber.log.Timber; -public class BooksAdapter extends RecyclerView.Adapter { +public class BooksAdapter extends RecyclerView.Adapter +{ private WeakReference context; private List books; private BookItemListener itemListener; - public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener { + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener + { - @Bind(R.id.titleTextView) TextView titleTextView; - @Bind(R.id.authorTextView) TextView authorTextView; - @Bind(R.id.publishedTextView) TextView publishedTextView; - @Bind(R.id.pagesTextView) TextView pagesTextView; - @Bind(R.id.imageView) ImageView imageView; + @BindView(R.id.titleTextView) TextView titleTextView; + @BindView(R.id.authorTextView) TextView authorTextView; + @BindView(R.id.publishedTextView) TextView publishedTextView; + @BindView(R.id.pagesTextView) TextView pagesTextView; + @BindView(R.id.imageView) ImageView imageView; BookItemListener itemListener; - public ViewHolder(View v, BookItemListener itemListener) { + ViewHolder(View v, BookItemListener itemListener) + { super(v); ButterKnife.bind(this, v); @@ -67,14 +72,17 @@ public void onClick (View v) } } - public BooksAdapter (Context context, List books, BookItemListener itemListener) { + BooksAdapter(Context context, List books, BookItemListener itemListener) + { this.context = new WeakReference<>(context); this.books = books; this.itemListener = itemListener; } + @NotNull @Override - public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { + public ViewHolder onCreateViewHolder(@NotNull ViewGroup viewGroup, int viewType) + { View v = LayoutInflater.from(viewGroup.getContext()) .inflate(R.layout.book_row_item, viewGroup, false); @@ -82,7 +90,8 @@ public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { } @Override - public void onBindViewHolder(ViewHolder viewHolder, final int position) { + public void onBindViewHolder(@NotNull ViewHolder viewHolder, final int position) + { Timber.d("Element " + position + " set."); Book book = books.get(position); @@ -96,7 +105,7 @@ public void onBindViewHolder(ViewHolder viewHolder, final int position) { viewHolder.pagesTextView.setText( String.format(contextLocal.getString(R.string.pages_label), book.getNumberOfPages())); - Picasso.with(contextLocal) + Picasso.get() .load(book.getImageUrl()) .resize(80, 108) .centerInside() @@ -105,20 +114,24 @@ public void onBindViewHolder(ViewHolder viewHolder, final int position) { } @Override - public int getItemCount() { + public int getItemCount() + { return books.size(); } - public void updateBooks(List books) { + void updateBooks(List books) + { this.books = books; notifyDataSetChanged(); } - private Book getItem(int adapterPosition) { + private Book getItem(int adapterPosition) + { return books.get(adapterPosition); } - public interface BookItemListener { + public interface BookItemListener + { void onBookClick(long id); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java index abb3dbe..6759fe3 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksContract.java @@ -13,9 +13,9 @@ public interface BooksContract interface View { - void showBooks (List books); + void showBooks(List books); - void showErrorMessage (); + void showErrorMessage(); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java index 8a8fec0..4915e75 100644 --- a/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java +++ b/app/src/main/java/info/adavis/adeptandroid/books/BooksPresenter.java @@ -9,38 +9,38 @@ import retrofit2.Response; import timber.log.Timber; -public class BooksPresenter +class BooksPresenter { private final BooksContract.View booksView; private final BookService service; - public BooksPresenter (BooksContract.View booksView, BookService service) + BooksPresenter(BooksContract.View booksView, BookService service) { this.booksView = booksView; this.service = service; } - public void initDataSet () + void initDataSet() { - service.getBooks().enqueue( new Callback>() + service.getBooks().enqueue(new Callback>() { @Override - public void onResponse (Call> call, Response> response) + public void onResponse(Call> call, Response> response) { - if ( response.isSuccessful() ) + if (response.isSuccessful()) { - booksView.showBooks( response.body() ); - Timber.i( "Books data was loaded from API." ); + booksView.showBooks(response.body()); + Timber.i("Books data was loaded from API."); } } @Override - public void onFailure (Call> call, Throwable t) + public void onFailure(Call> call, Throwable t) { booksView.showErrorMessage(); - Timber.e( t, "Unable to load the books data from API." ); + Timber.e(t, "Unable to load the books data from API."); } - } ); + }); } } \ No newline at end of file diff --git a/app/src/main/java/info/adavis/adeptandroid/data/BookService.java b/app/src/main/java/info/adavis/adeptandroid/data/BookService.java index a6ee0bb..71bfc82 100644 --- a/app/src/main/java/info/adavis/adeptandroid/data/BookService.java +++ b/app/src/main/java/info/adavis/adeptandroid/data/BookService.java @@ -13,12 +13,13 @@ */ public interface BookService { - @GET( "books" ) + + @GET("books") Call> getBooks(); - @GET( "books" ) - Call> search( @Query( "q" ) String query ); + @GET("books") + Call> search(@Query("q") String query); - @GET( "books/{id}" ) - Call getBook( @Path( "id" ) Long id ); + @GET("books/{id}") + Call getBook(@Path("id") Long id); } diff --git a/app/src/main/java/info/adavis/adeptandroid/di/Injector.java b/app/src/main/java/info/adavis/adeptandroid/di/Injector.java index e174043..b97740b 100644 --- a/app/src/main/java/info/adavis/adeptandroid/di/Injector.java +++ b/app/src/main/java/info/adavis/adeptandroid/di/Injector.java @@ -10,17 +10,18 @@ */ public class Injector { - public static Retrofit provideRetrofit (String baseUrl) + + public static Retrofit provideRetrofit(String baseUrl) { return new Retrofit.Builder() - .baseUrl( baseUrl ) - .addConverterFactory( GsonConverterFactory.create() ) + .baseUrl(baseUrl) + .addConverterFactory(GsonConverterFactory.create()) .build(); } - public static BookService provideBookService () + public static BookService provideBookService() { - return provideRetrofit( Constants.BASE_URL ).create( BookService.class ); + return provideRetrofit(Constants.BASE_URL).create(BookService.class); } } diff --git a/app/src/main/java/info/adavis/adeptandroid/models/Book.java b/app/src/main/java/info/adavis/adeptandroid/models/Book.java index b63c4b9..e395b20 100644 --- a/app/src/main/java/info/adavis/adeptandroid/models/Book.java +++ b/app/src/main/java/info/adavis/adeptandroid/models/Book.java @@ -1,5 +1,6 @@ package info.adavis.adeptandroid.models; +import org.jetbrains.annotations.NotNull; public class Book { @@ -39,6 +40,7 @@ public int getNumberOfPages() { return numberOfPages; } + @NotNull @Override public String toString() { return "Book{" + diff --git a/build.gradle b/build.gradle index 03bced9..9d4c52c 100644 --- a/build.gradle +++ b/build.gradle @@ -2,10 +2,12 @@ buildscript { repositories { + google() + mavenCentral() jcenter() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' + classpath 'com.android.tools.build:gradle:3.4.1' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files @@ -14,6 +16,8 @@ buildscript { allprojects { repositories { + google() + mavenCentral() jcenter() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 9c5eb69..1757b9a 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip