diff --git a/app/build.gradle b/app/build.gradle index 350d0ab..fe1920a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -24,4 +24,18 @@ dependencies { compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:design:22.2.0' compile 'com.android.support:recyclerview-v7:22.2.0' + + compile 'com.squareup.retrofit:retrofit:1.9.0' + compile 'com.squareup.okhttp:okhttp-urlconnection:2.4.0' + compile 'com.squareup.okhttp:okhttp:2.4.0' + + compile 'com.github.bumptech.glide:glide:3.6.0' + compile 'com.github.bumptech.glide:okhttp-integration:1.3.1' + + compile 'de.halfbit:tinybus:3.0.1' + + compile('de.keyboardsurfer.android.widget:crouton:1.8.5@aar') { + // exclusion is not necessary, but generally a good idea. + exclude group: 'com.google.android', module: 'support-v4' + } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b52b269..fc2f1fc 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -18,4 +18,6 @@ + + diff --git a/app/src/main/java/android/coding/interview/makeitawesome/MainActivity.java b/app/src/main/java/android/coding/interview/makeitawesome/MainActivity.java index 3a779fa..a7f2e5c 100644 --- a/app/src/main/java/android/coding/interview/makeitawesome/MainActivity.java +++ b/app/src/main/java/android/coding/interview/makeitawesome/MainActivity.java @@ -1,5 +1,7 @@ package android.coding.interview.makeitawesome; +import android.app.FragmentTransaction; +import android.coding.interview.makeitawesome.fragment.DetailFragment; import android.coding.interview.makeitawesome.fragment.PicturesFragment; import android.coding.interview.makeitawesome.fragment.WelcomeScreenFragment; import android.os.Bundle; @@ -74,6 +76,7 @@ public boolean onNavigationItemSelected(MenuItem menuItem) { if (fm.findFragmentByTag("PICTURES_FRAGMENT") == null) { // no pictures shown yet, show it fm.beginTransaction().replace(R.id.content_frame, PicturesFragment.newInstance(), "PICTURES_FRAGMENT").addToBackStack(null).commit(); } + } mDrawerLayout.closeDrawers(); diff --git a/app/src/main/java/android/coding/interview/makeitawesome/adapter/PhotosAdapter.java b/app/src/main/java/android/coding/interview/makeitawesome/adapter/PhotosAdapter.java index 366168c..08b0b42 100644 --- a/app/src/main/java/android/coding/interview/makeitawesome/adapter/PhotosAdapter.java +++ b/app/src/main/java/android/coding/interview/makeitawesome/adapter/PhotosAdapter.java @@ -1,23 +1,51 @@ package android.coding.interview.makeitawesome.adapter; + import android.coding.interview.makeitawesome.R; +import android.coding.interview.makeitawesome.fragment.DetailFragment; +import android.coding.interview.makeitawesome.model.Album; +import android.graphics.Bitmap; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.ImageView; import android.widget.TextView; -import java.util.Arrays; +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; + +import java.util.ArrayList; import java.util.List; /** * adapter keeping data for list of photos */ public class PhotosAdapter extends RecyclerView.Adapter { - - // TODO this is a dummy data that you have to replace. You probably need List of some objects representing pictures - // rather than just strings - private List mData = Arrays.asList("dummy 1", "dummy 2", "dummy 3", "dummy 4", "etc"); + + private List mData = null; + android.support.v4.app.FragmentManager fragmentManager; + + public android.support.v4.app.FragmentManager getFragmentManager() { + return fragmentManager; + } + + public void setFragmentManager(android.support.v4.app.FragmentManager fragmentManager) { + this.fragmentManager = fragmentManager; + } + + public List getmData() { + return mData; + } + + public void setmData(List mData) { + this.mData = mData; + } + + public PhotosAdapter() { + mData = new ArrayList(); + } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int i) { @@ -27,7 +55,15 @@ public ViewHolder onCreateViewHolder(ViewGroup parent, int i) { @Override public void onBindViewHolder(ViewHolder holder, int i) { - holder.mText.setText(mData.get(i)); + holder.mText.setText(mData.get(i).getTitle()); + + final ImageView img = holder.mImage; + Glide.with(holder.mImage.getContext()).load(mData.get(i).getThumbnailUrl()).asBitmap().into(new SimpleTarget(80, 80) { + @Override + public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { + img.setImageBitmap(resource); + } + }); } @Override @@ -35,11 +71,25 @@ public int getItemCount() { return mData.size(); } - public static class ViewHolder extends RecyclerView.ViewHolder { + + + + public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ + final TextView mText; + final ImageView mImage; + public ViewHolder(View itemView) { super(itemView); - mText = (TextView) itemView; + itemView.setOnClickListener(this); + mText = (TextView) itemView.findViewById(R.id.item_title); + mImage = (ImageView) itemView.findViewById(R.id.item_icon); + } + + @Override + public void onClick(final View view) { + int itemPosition = getPosition(); + fragmentManager.beginTransaction().replace(R.id.content_frame,DetailFragment.newInstance(mData.get(itemPosition)), "PICTURES_FRAGMENT").addToBackStack(null).commit(); } } } diff --git a/app/src/main/java/android/coding/interview/makeitawesome/fragment/DetailFragment.java b/app/src/main/java/android/coding/interview/makeitawesome/fragment/DetailFragment.java new file mode 100644 index 0000000..c7339d9 --- /dev/null +++ b/app/src/main/java/android/coding/interview/makeitawesome/fragment/DetailFragment.java @@ -0,0 +1,59 @@ +package android.coding.interview.makeitawesome.fragment; + +import android.coding.interview.makeitawesome.R; +import android.coding.interview.makeitawesome.model.Album; +import android.graphics.Bitmap; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; + +import com.bumptech.glide.Glide; +import com.bumptech.glide.request.animation.GlideAnimation; +import com.bumptech.glide.request.target.SimpleTarget; + + +public class DetailFragment extends Fragment { + + public static Fragment newInstance(Album album) { + DetailFragment detail = new DetailFragment(); + detail.setAlbum(album); + detail.setRetainInstance(true); + return detail; + } + + public Album getAlbum() { + return album; + } + + public void setAlbum(Album album) { + this.album = album; + } + + Album album; + ImageView mImage; + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { + View v = inflater.inflate(R.layout.picture_detail, container, false); + mImage = (ImageView) v.findViewById(R.id.item_icon); + showImage(); + return v; + } + + + public void showImage() { + + Glide.with(getActivity()).load(album.getUrl()).asBitmap().into(new SimpleTarget(350, 350) { + @Override + public void onResourceReady(Bitmap resource, GlideAnimation glideAnimation) { + mImage.setImageBitmap(resource); + } + }); + } + +} diff --git a/app/src/main/java/android/coding/interview/makeitawesome/fragment/PicturesFragment.java b/app/src/main/java/android/coding/interview/makeitawesome/fragment/PicturesFragment.java index 32a7c34..5ec6735 100644 --- a/app/src/main/java/android/coding/interview/makeitawesome/fragment/PicturesFragment.java +++ b/app/src/main/java/android/coding/interview/makeitawesome/fragment/PicturesFragment.java @@ -1,7 +1,11 @@ package android.coding.interview.makeitawesome.fragment; +import android.app.ProgressDialog; import android.coding.interview.makeitawesome.R; import android.coding.interview.makeitawesome.adapter.PhotosAdapter; +import android.coding.interview.makeitawesome.model.Album; +import android.coding.interview.makeitawesome.networking.AlbumEvent; +import android.coding.interview.makeitawesome.networking.RestClient; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v4.app.Fragment; @@ -11,6 +15,13 @@ import android.view.View; import android.view.ViewGroup; +import java.util.List; + +import de.halfbit.tinybus.Subscribe; +import de.halfbit.tinybus.TinyBus; +import de.keyboardsurfer.android.widget.crouton.Crouton; +import de.keyboardsurfer.android.widget.crouton.Style; + /** * This is Your TASK:
* This is a fragment where you need to show list of pictures and details fetched from API
@@ -19,19 +30,78 @@ public class PicturesFragment extends Fragment { public static Fragment newInstance() { - return new PicturesFragment(); + PicturesFragment pictures = new PicturesFragment(); + pictures.setRetainInstance(true); + return pictures; } + RecyclerView rv; + ProgressDialog mProgressDialog; + List mData; + boolean loading = false; + private TinyBus mBus; + @Nullable @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - RecyclerView rv = (RecyclerView) inflater.inflate(R.layout.pictures_list_fragment, container, false); - setupRecyclerView(rv); + rv = (RecyclerView) inflater.inflate(R.layout.pictures_list_fragment, container, false); + + if (mProgressDialog != null && mProgressDialog.isShowing()) + mProgressDialog.dismiss(); + + mProgressDialog = new ProgressDialog(container.getContext()); + mProgressDialog.setIndeterminate(true); + mProgressDialog.setMessage("Loading..."); + mProgressDialog.show(); + + mBus = TinyBus.from(getActivity()); + + if (mData == null) { + if (!loading) { + RestClient restClient = RestClient.getInstance(); + restClient.getPhotos(mBus); + loading = true; + } + } else { + drawList(); + } return rv; } - private void setupRecyclerView(RecyclerView recyclerView) { - recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext())); - recyclerView.setAdapter(new PhotosAdapter()); + @Override + public void onResume() { + super.onResume(); + mBus.register(this); } + + @Override + public void onPause() { + super.onPause(); + mBus.unregister(this); + } + + @Subscribe + public void onAlbumEvent(AlbumEvent apiEvent) { + + if (mProgressDialog.isShowing()) + mProgressDialog.dismiss(); + if (apiEvent.getError() != null) { + Crouton.makeText(getActivity(), apiEvent.getError().getMessage(), Style.ALERT).show(); + } else { + mData = apiEvent.getObject(); + drawList(); + } + loading = false; + } + + public void drawList() { + if (mProgressDialog.isShowing()) + mProgressDialog.dismiss(); + rv.setLayoutManager(new LinearLayoutManager(rv.getContext())); + PhotosAdapter photosAdapter = new PhotosAdapter(); + photosAdapter.setmData(mData); + photosAdapter.setFragmentManager(getActivity().getSupportFragmentManager()); + rv.setAdapter(photosAdapter); + } + } diff --git a/app/src/main/java/android/coding/interview/makeitawesome/model/Album.java b/app/src/main/java/android/coding/interview/makeitawesome/model/Album.java new file mode 100644 index 0000000..da3fff0 --- /dev/null +++ b/app/src/main/java/android/coding/interview/makeitawesome/model/Album.java @@ -0,0 +1,69 @@ +package android.coding.interview.makeitawesome.model; + +/** + * Created by antonio on 24/07/15. + */ +public class Album { + + private int albumId; + private int id; + private String title; + private String url; + private String thumbnailUrl; + + public Album() { + this.albumId = -1; + this.id = -1; + this.title = ""; + this.url = ""; + this.thumbnailUrl = ""; + } + + public Album(int albumId, int id, String title, String url, String thumbnailUrl) { + this.albumId = albumId; + this.id = id; + this.title = title; + this.url = url; + this.thumbnailUrl = thumbnailUrl; + } + + public int getAlbumId() { + return albumId; + } + + public void setAlbumId(int albumId) { + this.albumId = albumId; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public String getThumbnailUrl() { + return thumbnailUrl; + } + + public void setThumbnailUrl(String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } +} diff --git a/app/src/main/java/android/coding/interview/makeitawesome/networking/AlbumEvent.java b/app/src/main/java/android/coding/interview/makeitawesome/networking/AlbumEvent.java new file mode 100644 index 0000000..c2056e6 --- /dev/null +++ b/app/src/main/java/android/coding/interview/makeitawesome/networking/AlbumEvent.java @@ -0,0 +1,31 @@ +package android.coding.interview.makeitawesome.networking; + +import android.coding.interview.makeitawesome.model.Album; + +import java.util.List; + +import retrofit.RetrofitError; + +/** + * Created by antonio on 26/07/15. + */ +public class AlbumEvent { + private List albums; + private RetrofitError error; + + public AlbumEvent(List albums) { + this.albums = albums; + } + + public AlbumEvent(RetrofitError error) { + this.error = error; + } + + public Exception getError() { + return error; + } + + public List getObject() { + return albums; + } +} diff --git a/app/src/main/java/android/coding/interview/makeitawesome/networking/ApiPhoto.java b/app/src/main/java/android/coding/interview/makeitawesome/networking/ApiPhoto.java new file mode 100644 index 0000000..cb41521 --- /dev/null +++ b/app/src/main/java/android/coding/interview/makeitawesome/networking/ApiPhoto.java @@ -0,0 +1,18 @@ +package android.coding.interview.makeitawesome.networking; + +import android.coding.interview.makeitawesome.model.Album; + +import java.util.List; + +import retrofit.Callback; +import retrofit.http.GET; + +/** + * Created by antonio on 24/07/15. + */ +public interface ApiPhoto { + + @GET("/") + public void listPhotos(Callback> callback); + +} diff --git a/app/src/main/java/android/coding/interview/makeitawesome/networking/RestClient.java b/app/src/main/java/android/coding/interview/makeitawesome/networking/RestClient.java new file mode 100644 index 0000000..324ed08 --- /dev/null +++ b/app/src/main/java/android/coding/interview/makeitawesome/networking/RestClient.java @@ -0,0 +1,86 @@ +package android.coding.interview.makeitawesome.networking; + +import android.coding.interview.makeitawesome.model.Album; + +import com.squareup.okhttp.Cache; +import com.squareup.okhttp.OkHttpClient; + +import java.io.File; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.TimeUnit; + +import de.halfbit.tinybus.TinyBus; +import retrofit.Callback; +import retrofit.RequestInterceptor; +import retrofit.RestAdapter; +import retrofit.RetrofitError; +import retrofit.android.AndroidLog; +import retrofit.client.OkClient; +import retrofit.client.Response; + +/** + * Created by antonio on 24/07/15. + */ +public class RestClient { + + private ApiPhoto api; + + + public static RestClient restClient= null; + private static final String URL = "http://jsonplaceholder.typicode.com/photos/"; + + protected RestClient(){ + + OkHttpClient okHttpClient = new OkHttpClient(); + File cacheDir = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()); + Cache cache = null; + cache = new Cache(cacheDir, 10 * 1024 * 1024); + + + RequestInterceptor requestInterceptor = new RequestInterceptor() { + @Override + public void intercept(RequestFacade request) { + request.addHeader("content-type", "application/json"); + request.addHeader("accept-encoding", "gzip"); // Here is the problem + } + }; + + okHttpClient.setCache(cache); + okHttpClient.setConnectTimeout(60000, TimeUnit.MILLISECONDS); + okHttpClient.setReadTimeout(60000, TimeUnit.MILLISECONDS); + + RestAdapter restAdapter = new RestAdapter.Builder() + .setEndpoint(URL) + .setClient(new OkClient(okHttpClient)) + .setRequestInterceptor(requestInterceptor) + .setLogLevel(RestAdapter.LogLevel.FULL) + .setLog(new AndroidLog("RETROFIT")) + .build(); + api = restAdapter.create(ApiPhoto.class); + } + + public static synchronized RestClient getInstance(){ + if(restClient==null){ + restClient = new RestClient(); + } + return restClient; + } + + public void getPhotos(final TinyBus mBus){ + + api.listPhotos(new Callback>() { + + @Override + public void success(List albums, Response response) { + mBus.post(new AlbumEvent(albums)); + } + + @Override + public void failure(RetrofitError error) { + mBus.post(new AlbumEvent(error)); + } + }); + } + +} diff --git a/app/src/main/res/layout/picture_detail.xml b/app/src/main/res/layout/picture_detail.xml new file mode 100644 index 0000000..d32b816 --- /dev/null +++ b/app/src/main/res/layout/picture_detail.xml @@ -0,0 +1,22 @@ + + + + + + + + + + diff --git a/app/src/main/res/layout/picture_list_item.xml b/app/src/main/res/layout/picture_list_item.xml index 6b5a158..86dc12a 100644 --- a/app/src/main/res/layout/picture_list_item.xml +++ b/app/src/main/res/layout/picture_list_item.xml @@ -1,11 +1,35 @@ - - - + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/pictures_list_fragment.xml b/app/src/main/res/layout/pictures_list_fragment.xml index c0d3489..de838fb 100644 --- a/app/src/main/res/layout/pictures_list_fragment.xml +++ b/app/src/main/res/layout/pictures_list_fragment.xml @@ -1,10 +1,9 @@ - -