Skip to content

Commit

Permalink
Add images
Browse files Browse the repository at this point in the history
  • Loading branch information
artem-zinnatullin committed Nov 29, 2015
1 parent ff42c0e commit 4ddebca
Show file tree
Hide file tree
Showing 29 changed files with 315 additions and 83 deletions.
1 change: 1 addition & 0 deletions app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ dependencies {
compile libraries.supportCardView

compile libraries.butterKnife
compile libraries.picasso

testCompile libraries.junit
testCompile libraries.robolectric
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ public void afterEachTest() throws IOException {
@Test
public void items_shouldHandleCorrectResponse() {
mockWebServer.enqueue(new MockResponse().setBody("["
+ "{ \"id\": \"test_id_1\", \"title\": \"Test title 1\", \"short_description\": \"Short desc 1\"},"
+ "{ \"id\": \"test_id_2\", \"title\": \"Test title 2\", \"short_description\": \"Short desc 2\"},"
+ "{ \"id\": \"test_id_3\", \"title\": \"Test title 3\", \"short_description\": \"Short desc 3\"}"
+ "{ \"id\": \"test_id_1\", \"image_preview_url\": \"https://url1\", \"title\": \"Test title 1\", \"short_description\": \"Short desc 1\"},"
+ "{ \"id\": \"test_id_2\", \"image_preview_url\": \"https://url2\", \"title\": \"Test title 2\", \"short_description\": \"Short desc 2\"},"
+ "{ \"id\": \"test_id_3\", \"image_preview_url\": \"https://url3\", \"title\": \"Test title 3\", \"short_description\": \"Short desc 3\"}"
+ "]"));

// Get items from the API
Expand All @@ -71,14 +71,17 @@ public void items_shouldHandleCorrectResponse() {
assertThat(items).hasSize(3);

assertThat(items.get(0).id()).isEqualTo("test_id_1");
assertThat(items.get(0).imagePreviewUrl()).isEqualTo("https://url1");
assertThat(items.get(0).title()).isEqualTo("Test title 1");
assertThat(items.get(0).shortDescription()).isEqualTo("Short desc 1");

assertThat(items.get(1).id()).isEqualTo("test_id_2");
assertThat(items.get(1).imagePreviewUrl()).isEqualTo("https://url2");
assertThat(items.get(1).title()).isEqualTo("Test title 2");
assertThat(items.get(1).shortDescription()).isEqualTo("Short desc 2");

assertThat(items.get(2).id()).isEqualTo("test_id_3");
assertThat(items.get(2).imagePreviewUrl()).isEqualTo("https://url3");
assertThat(items.get(2).title()).isEqualTo("Test title 3");
assertThat(items.get(2).shortDescription()).isEqualTo("Short desc 3");
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.artemzin.qualitymatters.integration_tests.api.entities;

import com.artemzin.qualitymatters.QualityMattersRobolectricTestRunner;
import com.artemzin.qualitymatters.api.entities.Item;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.IOException;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(QualityMattersRobolectricTestRunner.class)
public class ItemTest {

// Why test JSON serialization/deserialization?
// 1. Update JSON libraries without worrying about breaking changes.
// 2. Be sure that @JsonIgnore and similar annotations do not affect expected behavior (cc @karlicos).
@Test
public void fromJson() throws IOException {
ObjectMapper objectMapper = QualityMattersRobolectricTestRunner.qualityMattersApp().applicationComponent().objectMapper();

Item item = objectMapper.readValue("{ " +
"\"id\": \"test_id\", " +
"\"image_preview_url\": \"some_url\"," +
"\"title\": \"Test title\", " +
"\"short_description\": \"Test short description\"" +
"}",
Item.class);

assertThat(item.id()).isEqualTo("test_id");
assertThat(item.imagePreviewUrl()).isEqualTo("some_url");
assertThat(item.title()).isEqualTo("Test title");
assertThat(item.shortDescription()).isEqualTo("Test short description");
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import android.support.annotation.NonNull;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.squareup.picasso.Picasso;

import javax.inject.Named;
import javax.inject.Singleton;
Expand Down Expand Up @@ -39,4 +40,9 @@ public ObjectMapper provideObjectMapper() {
public Handler provideMainThreadHandler() {
return new Handler(Looper.getMainLooper());
}

@Provides @NonNull @Singleton
public Picasso providePicasso(@NonNull QualityMattersApp qualityMattersApp) {
return Picasso.with(qualityMattersApp);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
public abstract class Item {

private static final String JSON_PROPERTY_ID = "id";
private static final String JSON_PROPERTY_IMAGE_PREVIEW_URL = "image_preview_url";
private static final String JSON_PROPERTY_TITLE = "title";
private static final String JSON_PROPERTY_SHORT_DESCRIPTION = "short_description";

Expand All @@ -25,6 +26,10 @@ public static Builder builder() {
@JsonProperty(JSON_PROPERTY_ID)
public abstract String id();

@NonNull
@JsonProperty(JSON_PROPERTY_IMAGE_PREVIEW_URL)
public abstract String imagePreviewUrl();

@NonNull
@JsonProperty(JSON_PROPERTY_TITLE)
public abstract String title();
Expand All @@ -40,6 +45,10 @@ public static abstract class Builder {
@JsonProperty(JSON_PROPERTY_ID)
public abstract Builder id(@NonNull String id);

@NonNull
@JsonProperty(JSON_PROPERTY_IMAGE_PREVIEW_URL)
public abstract Builder imagePreviewUrl(@NonNull String imagePreviewUrl);

@NonNull
@JsonProperty(JSON_PROPERTY_TITLE)
public abstract Builder title(@NonNull String title);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.artemzin.qualitymatters.ui.adapters;

import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import com.artemzin.qualitymatters.R;
import com.artemzin.qualitymatters.api.entities.Item;
import com.squareup.picasso.Picasso;

import butterknife.Bind;
import butterknife.ButterKnife;

class ItemViewHolder extends RecyclerView.ViewHolder {

@NonNull
private final Picasso picasso;

@Bind(R.id.list_item_image_view)
ImageView imageView;

@Bind(R.id.list_item_title_text_view)
TextView titleTextView;

@Bind(R.id.list_item_short_description_text_view)
TextView shortDescriptionTextView;

public ItemViewHolder(@NonNull View itemView, @NonNull Picasso picasso) {
super(itemView);
this.picasso = picasso;
ButterKnife.bind(this, itemView);
}

public void bind(@NonNull Item item) {
picasso.load(item.imagePreviewUrl()).fit().centerCrop().into(imageView);
titleTextView.setText(item.title());
shortDescriptionTextView.setText(item.shortDescription());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,31 @@
import android.support.annotation.NonNull;
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 com.artemzin.qualitymatters.R;
import com.artemzin.qualitymatters.api.entities.Item;
import com.squareup.picasso.Picasso;

import java.util.List;

import butterknife.Bind;
import butterknife.ButterKnife;

import static java.util.Collections.emptyList;
import static java.util.Collections.unmodifiableList;

public class ItemsAdapter extends RecyclerView.Adapter<ItemsAdapter.ItemViewHolder> {
public class ItemsAdapter extends RecyclerView.Adapter<ItemViewHolder> {

@NonNull
private final LayoutInflater layoutInflater;

@NonNull
private final Picasso picasso;

@NonNull
private List<Item> items = emptyList();

public ItemsAdapter(@NonNull LayoutInflater layoutInflater) {
public ItemsAdapter(@NonNull LayoutInflater layoutInflater, @NonNull Picasso picasso) {
this.layoutInflater = layoutInflater;
this.picasso = picasso;
}

@Override
Expand All @@ -43,33 +42,12 @@ public void setData(@NonNull List<Item> items) {

@Override @NonNull
public ItemViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
return new ItemViewHolder(layoutInflater.inflate(R.layout.list_item, parent, false));
return new ItemViewHolder(layoutInflater.inflate(R.layout.list_item, parent, false), picasso);
}

@Override
public void onBindViewHolder(@NonNull ItemViewHolder viewHolder, int position) {
viewHolder.bind(items.get(position));
}

static class ItemViewHolder extends RecyclerView.ViewHolder {

@Bind(R.id.list_item_image_view)
ImageView imageView;

@Bind(R.id.list_item_title_text_view)
TextView titleTextView;

@Bind(R.id.list_item_short_description_text_view)
TextView shortDescriptionTextView;

public ItemViewHolder(@NonNull View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
}

public void bind(@NonNull Item item) {
titleTextView.setText(item.title());
shortDescriptionTextView.setText(item.shortDescription());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,11 @@
import com.artemzin.qualitymatters.api.entities.Item;
import com.artemzin.qualitymatters.models.ItemsModel;
import com.artemzin.qualitymatters.ui.adapters.ItemsAdapter;
import com.artemzin.qualitymatters.ui.others.VerticalSpaceItemDecoration;
import com.artemzin.qualitymatters.ui.presenters.ItemsPresenter;
import com.artemzin.qualitymatters.ui.presenters.ItemsPresenterConfiguration;
import com.artemzin.qualitymatters.ui.views.ItemsView;
import com.squareup.picasso.Picasso;

import java.util.List;

Expand Down Expand Up @@ -76,6 +78,9 @@ public ItemsPresenter provideItemsPresenter(@NonNull ItemsModel itemsModel) {
@Inject
ItemsPresenter itemsPresenter;

@Inject
Picasso picasso;

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Expand All @@ -92,7 +97,8 @@ public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup c
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
ButterKnife.bind(this, view);
contentUiRecyclerView.setLayoutManager(new LinearLayoutManager(getContext(), VERTICAL, false));
itemsAdapter = new ItemsAdapter(getActivity().getLayoutInflater());
contentUiRecyclerView.addItemDecoration(new VerticalSpaceItemDecoration((int) getResources().getDimension(R.dimen.list_item_vertical_space_between_items)));
itemsAdapter = new ItemsAdapter(getActivity().getLayoutInflater(), picasso);
contentUiRecyclerView.setAdapter(itemsAdapter);
itemsPresenter.bindView(this);
itemsPresenter.reloadData();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.artemzin.qualitymatters.ui.others;

import android.graphics.Rect;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.View;

public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {

private final int verticalSpacePx;

public VerticalSpaceItemDecoration(int verticalSpacePx) {
this.verticalSpacePx = verticalSpacePx;
}

@Override
public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
outRect.bottom = verticalSpacePx;
}
}
3 changes: 3 additions & 0 deletions app/src/main/res/layout/fragment_items.xml
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,11 @@

<android.support.v7.widget.RecyclerView
android:id="@+id/items_content_ui"
android:background="@color/items_list_background"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:visibility="gone" />

</FrameLayout>
4 changes: 2 additions & 2 deletions app/src/main/res/layout/list_item.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/list_item_card_background"
android:minHeight="@dimen/list_item_min_height"
app:cardCornerRadius="@dimen/card_view_corner_radius">

<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/list_item_card_background">
android:layout_height="wrap_content">

<ImageView
android:id="@+id/list_item_image_view"
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/colors.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>

<color name="items_list_background">#dddddd</color>
<color name="list_item_card_background">#eeeeee</color>
<color name="list_item_title_background">#44000000</color>
<color name="list_item_title_text_color">#ffffff</color>
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
<dimen name="list_item_min_height">250dp</dimen>
<dimen name="list_item_image_height">150dp</dimen>
<dimen name="list_item_title_text_size">21sp</dimen>
<dimen name="list_item_vertical_space_between_items">8dp</dimen>
</resources>
Original file line number Diff line number Diff line change
@@ -1,46 +1,18 @@
package com.artemzin.qualitymatters.api.entities;

import com.artemzin.qualitymatters.QualityMattersRobolectricTestRunner;
import com.fasterxml.jackson.databind.ObjectMapper;

import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.IOException;

import nl.jqno.equalsverifier.EqualsVerifier;
import nl.jqno.equalsverifier.Warning;

import static org.assertj.core.api.Assertions.assertThat;

@RunWith(QualityMattersRobolectricTestRunner.class)
public class ItemTest {

// Why test JSON serialization/deserialization?
// 1. Update JSON libraries without worrying about breaking changes.
// 2. Be sure that @JsonIgnore and similar annotations do not affect expected behavior (cc @karlicos).
@Test
public void fromJson() throws IOException {
ObjectMapper objectMapper = QualityMattersRobolectricTestRunner.qualityMattersApp().applicationComponent().objectMapper();

Item item = objectMapper.readValue("{ " +
"\"id\": \"test_id\", " +
"\"title\": \"Test title\", " +
"\"short_description\": \"Test short description\"" +
"}",
Item.class);

assertThat(item.id()).isEqualTo("test_id");
assertThat(item.title()).isEqualTo("Test title");
assertThat(item.shortDescription()).isEqualTo("Test short description");
}

@Test
public void hashCode_equals_shouldWorkCorrectly() {
EqualsVerifier
.forExamples(
Item.builder().id("id1").title("Title1").shortDescription("s1").build(),
Item.builder().id("id2").title("Title2").shortDescription("s2").build())
Item.builder().id("id1").imagePreviewUrl("i1").title("Title1").shortDescription("s1").build(),
Item.builder().id("id2").imagePreviewUrl("i2").title("Title2").shortDescription("s2").build())
.suppress(Warning.NULL_FIELDS) // AutoValue checks nullability, EqualsVerifier does not expect that by default.
.verify();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,7 @@ public void beforeEachTest() {

@Test
public void getItems_shouldReturnItemsFromQualityMattersRestApi() {
List<Item> items = asList(
Item.builder().id("1").title("Item 1").shortDescription("s1").build(),
Item.builder().id("2").title("Item 2").shortDescription("s2").build()
);
List<Item> items = asList(mock(Item.class), mock(Item.class));
when(qualityMattersRestApi.items()).thenReturn(Single.just(items));

assertThat(itemsModel.getItems().toBlocking().value()).containsExactlyElementsOf(items);
Expand Down
Loading

0 comments on commit 4ddebca

Please sign in to comment.