From 92ff40fad4bfb00888439408b807f53d0de691da Mon Sep 17 00:00:00 2001 From: Sergio Gutierrez Date: Fri, 11 Dec 2015 12:17:04 +0100 Subject: [PATCH 1/7] Give some love to detail views --- sample/build.gradle | 3 +- sample/src/main/AndroidManifest.xml | 4 +- .../activity/CharacterDetailsActivity.java | 15 ++++-- .../presenter/CharacterDetailsPresenter.java | 6 +++ .../view/activity/ComicDetailsActivity.java | 11 ++++ .../view/presenter/ComicDetailsPresenter.java | 6 +++ .../main/view/activity/MainActivity.java | 6 +-- .../main/view/adapter/FragmentAdapter.java | 4 +- .../ic_chevron_left_white_48dp.png | Bin 0 -> 169 bytes .../ic_chevron_right_white_24dp.png | Bin 0 -> 133 bytes .../ic_keyboard_arrow_right_white_24dp.png | Bin 150 -> 0 bytes .../ic_chevron_left_white_48dp.png | Bin 0 -> 136 bytes .../ic_chevron_right_white_24dp.png | Bin 0 -> 113 bytes .../ic_keyboard_arrow_right_white_24dp.png | Bin 138 -> 0 bytes .../ic_chevron_left_white_48dp.png | Bin 0 -> 197 bytes .../ic_chevron_right_white_24dp.png | Bin 0 -> 144 bytes .../ic_keyboard_arrow_right_white_24dp.png | Bin 163 -> 0 bytes .../ic_chevron_left_white_48dp.png | Bin 0 -> 242 bytes .../ic_chevron_right_white_24dp.png | Bin 0 -> 175 bytes .../ic_keyboard_arrow_right_white_24dp.png | Bin 227 -> 0 bytes .../main/res/drawable/toolbar_gradient.xml | 24 +++++++++ .../drawable/view_pager_tab_background.xml | 39 -------------- .../res/layout/activity_character_details.xml | 41 +++++++++------ .../res/layout/activity_comic_details.xml | 41 +++++++++------ sample/src/main/res/layout/activity_main.xml | 5 +- sample/src/main/res/layout/item_character.xml | 2 +- sample/src/main/res/layout/item_comic.xml | 2 +- sample/src/main/res/layout/toolbar.xml | 48 ++++++++++++++++++ sample/src/main/res/values/colors.xml | 4 ++ sample/src/main/res/values/dimens.xml | 18 ++++--- sample/src/main/res/values/strings.xml | 1 + sample/src/main/res/values/styles.xml | 27 ++++++---- 32 files changed, 204 insertions(+), 103 deletions(-) create mode 100644 sample/src/main/res/drawable-hdpi/ic_chevron_left_white_48dp.png create mode 100644 sample/src/main/res/drawable-hdpi/ic_chevron_right_white_24dp.png delete mode 100644 sample/src/main/res/drawable-hdpi/ic_keyboard_arrow_right_white_24dp.png create mode 100644 sample/src/main/res/drawable-mdpi/ic_chevron_left_white_48dp.png create mode 100644 sample/src/main/res/drawable-mdpi/ic_chevron_right_white_24dp.png delete mode 100644 sample/src/main/res/drawable-mdpi/ic_keyboard_arrow_right_white_24dp.png create mode 100644 sample/src/main/res/drawable-xhdpi/ic_chevron_left_white_48dp.png create mode 100644 sample/src/main/res/drawable-xhdpi/ic_chevron_right_white_24dp.png delete mode 100644 sample/src/main/res/drawable-xhdpi/ic_keyboard_arrow_right_white_24dp.png create mode 100644 sample/src/main/res/drawable-xxhdpi/ic_chevron_left_white_48dp.png create mode 100644 sample/src/main/res/drawable-xxhdpi/ic_chevron_right_white_24dp.png delete mode 100644 sample/src/main/res/drawable-xxhdpi/ic_keyboard_arrow_right_white_24dp.png create mode 100644 sample/src/main/res/drawable/toolbar_gradient.xml delete mode 100644 sample/src/main/res/drawable/view_pager_tab_background.xml create mode 100644 sample/src/main/res/layout/toolbar.xml diff --git a/sample/build.gradle b/sample/build.gradle index 206d5eb4..ea86e470 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -36,9 +36,8 @@ dependencies { compile 'com.android.support:support-v13:23.1.1' compile 'com.android.support:design:23.1.1' compile 'com.squareup.picasso:picasso:2.5.2' - compile 'fr.avianey.com.viewpagerindicator:library:2.4.1@aar' compile 'com.karumi:dividers:1.0.3' - compile 'com.victor:lib:1.0.1' + compile 'com.victor:lib:1.0.1' // spinner provided 'com.squareup.dagger:dagger-compiler:1.2.2' compile project(':rosie') } diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index 63968d4a..c73559a9 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -26,12 +26,12 @@ android:allowBackup="true" android:icon="@mipmap/ic_logo_karumi" android:label="@string/app_name" - android:theme="@style/SampleTheme" + android:theme="@style/SampleStyle" > diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java b/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java index 117e5a11..c984cce6 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java @@ -23,6 +23,7 @@ import android.widget.ImageView; import android.widget.TextView; import butterknife.Bind; +import butterknife.OnClick; import com.karumi.rosie.sample.R; import com.karumi.rosie.sample.characters.CharactersModule; import com.karumi.rosie.sample.characters.view.presenter.CharacterDetailsPresenter; @@ -40,6 +41,7 @@ public class CharacterDetailsActivity extends RosieActivity private static final String CHARACTER_KEY_EXTRA = "CharacterDetailsActivity.CharacterKey"; + @Bind(R.id.tv_toolbar_title) TextView toolbarTitleView; @Bind(R.id.iv_character_image) ImageView characterHeaderView; @Bind(R.id.ll_character_detail) View characterDetailView; @Bind(R.id.tv_character_name) TextView characterNameView; @@ -79,15 +81,22 @@ public class CharacterDetailsActivity extends RosieActivity @Override public void showCharacterDetail(CharacterDetailViewModel character) { characterDetailView.setVisibility(View.VISIBLE); + toolbarTitleView.setText(character.getName()); Picasso.with(this) - .load(character.getHeaderImage()) - .fit() - .centerCrop() + .load(character.getHeaderImage()).fit().centerCrop() .into(characterHeaderView); characterNameView.setText(character.getName()); characterDescriptionView.setText(character.getDescription()); } + @Override public void close() { + finish(); + } + + @OnClick(R.id.iv_toolbar_back) public void onBackButtonClicked() { + presenter.onBackButtonClicked(); + } + public static void open(Context context, String characterKey) { Intent intent = new Intent(context, CharacterDetailsActivity.class); intent.putExtra(CHARACTER_KEY_EXTRA, characterKey); diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/view/presenter/CharacterDetailsPresenter.java b/sample/src/main/java/com/karumi/rosie/sample/characters/view/presenter/CharacterDetailsPresenter.java index 2662ba60..65fd681e 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/characters/view/presenter/CharacterDetailsPresenter.java +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/view/presenter/CharacterDetailsPresenter.java @@ -50,6 +50,10 @@ public void setCharacterKey(String characterKey) { this.characterKey = characterKey; } + public void onBackButtonClicked() { + getView().close(); + } + private void loadCharacterDetails() { getView().hideCharacterDetail(); createUseCaseCall(getCharacterDetails).args(characterKey).onSuccess(new OnSuccessCallback() { @@ -66,5 +70,7 @@ public interface View extends RosiePresenterWithLoading.View { void hideCharacterDetail(); void showCharacterDetail(CharacterDetailViewModel character); + + void close(); } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicDetailsActivity.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicDetailsActivity.java index 9507690d..f05665fe 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicDetailsActivity.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicDetailsActivity.java @@ -23,6 +23,7 @@ import android.widget.ImageView; import android.widget.TextView; import butterknife.Bind; +import butterknife.OnClick; import com.karumi.rosie.sample.R; import com.karumi.rosie.sample.comics.ComicsModule; import com.karumi.rosie.sample.comics.view.presenter.ComicDetailsPresenter; @@ -40,6 +41,7 @@ public class ComicDetailsActivity extends RosieActivity implements ComicDetailsP private static final String COMIC_KEY_EXTRA = "ComicDetailsActivity.ComicKey"; private static final int INVALID_COMIC_KEY_EXTRA = -1; + @Bind(R.id.tv_toolbar_title) TextView toolbarTitleView; @Bind(R.id.ll_comic_detail) View comicView; @Bind(R.id.iv_cover) ImageView coverView; @Bind(R.id.tv_rating) TextView ratingView; @@ -79,11 +81,20 @@ public class ComicDetailsActivity extends RosieActivity implements ComicDetailsP @Override public void showComicDetails(ComicDetailsViewModel comic) { Picasso.with(this).load(comic.getCoverUrl()).fit().centerCrop().into(coverView); String rating = getString(comic.getRatingNameResourceId()); + toolbarTitleView.setText(comic.getTitle()); ratingView.setText(getString(R.string.marvel_rating_text, rating)); descriptionView.setText(comic.getDescription()); comicView.setVisibility(View.VISIBLE); } + @Override public void close() { + finish(); + } + + @OnClick(R.id.iv_toolbar_back) public void onBackButtonClicked() { + presenter.onBackButtonClicked(); + } + public static void open(Context context, int comicKey) { Intent intent = new Intent(context, ComicDetailsActivity.class); intent.putExtra(COMIC_KEY_EXTRA, comicKey); diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/presenter/ComicDetailsPresenter.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/presenter/ComicDetailsPresenter.java index 89a9b646..d225e7a9 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/presenter/ComicDetailsPresenter.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/presenter/ComicDetailsPresenter.java @@ -44,6 +44,10 @@ public void setComicKey(int comicKey) { this.comicKey = comicKey; } + public void onBackButtonClicked() { + getView().close(); + } + @Override protected void update() { super.update(); showLoading(); @@ -66,5 +70,7 @@ public interface View extends RosiePresenterWithLoading.View { void hideComicDetails(); void showComicDetails(ComicDetailsViewModel comic); + + void close(); } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java b/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java index b29ea8a9..ab46652e 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java +++ b/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java @@ -18,6 +18,7 @@ import android.app.Fragment; import android.os.Bundle; +import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; import butterknife.Bind; import com.karumi.rosie.sample.R; @@ -26,14 +27,13 @@ import com.karumi.rosie.sample.main.MainModule; import com.karumi.rosie.sample.main.view.adapter.FragmentAdapter; import com.karumi.rosie.view.RosieActivity; -import com.viewpagerindicator.TabPageIndicator; import java.util.Arrays; import java.util.List; public class MainActivity extends RosieActivity { @Bind(R.id.vp_main) ViewPager viewPager; - @Bind(R.id.tab_page_indicator) TabPageIndicator pagerTabView; + @Bind(R.id.tab_page_indicator) TabLayout pagerTabView; private FragmentAdapter adapter; @Override protected int getLayoutId() { @@ -59,6 +59,6 @@ private void initializeViewPager() { adapter.addFragment(comicsFragment, getString(R.string.comics_page_title)); adapter.notifyDataSetChanged(); - pagerTabView.setViewPager(viewPager); + pagerTabView.setupWithViewPager(viewPager); } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/main/view/adapter/FragmentAdapter.java b/sample/src/main/java/com/karumi/rosie/sample/main/view/adapter/FragmentAdapter.java index 4d136c5a..81da066d 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/main/view/adapter/FragmentAdapter.java +++ b/sample/src/main/java/com/karumi/rosie/sample/main/view/adapter/FragmentAdapter.java @@ -18,11 +18,11 @@ import android.app.Fragment; import android.app.FragmentManager; -import android.support.v13.app.FragmentStatePagerAdapter; +import android.support.v13.app.FragmentPagerAdapter; import java.util.ArrayList; import java.util.List; -public class FragmentAdapter extends FragmentStatePagerAdapter { +public class FragmentAdapter extends FragmentPagerAdapter { private final List fragments = new ArrayList<>(); diff --git a/sample/src/main/res/drawable-hdpi/ic_chevron_left_white_48dp.png b/sample/src/main/res/drawable-hdpi/ic_chevron_left_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..7141cc6186b2f90e2a33d59b824c5fcb2fe5fefa GIT binary patch literal 169 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhaw3OrpLLo)8Yy|I&*$&rEOVDAH^ z2A@hZe}!oW4_YKDIcyFpWl8-mF-gVq()`nB-aJxSskqldcZuxs#xKV_^KS04V3z@d zIiijp@{`_qte({8;SsNBJ0VOpH+D(z_5T*-vWrf?&@{fT=s8K{?+SJ0>t5gQcGrXf P?PlbP0l+XkK&k;Vz literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-hdpi/ic_chevron_right_white_24dp.png b/sample/src/main/res/drawable-hdpi/ic_chevron_right_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..1f10ee461a67bba9b40bc70c6f8c468c62d969ff GIT binary patch literal 133 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K;kEe@ch{y4_7awvqC@`=lDjqy` zt?bgBcUl?E^Co`GYj}UY^}!vTz!O|)k6&pXbz|k0wldT1B8K8tfz}(h{y4_=Nx$(3l_cC#w*DL-*Aw)=oKZn%`M1~4TB3j!F?hQAxvXbP0l+XkKZbLLy literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-mdpi/ic_chevron_right_white_24dp.png b/sample/src/main/res/drawable-mdpi/ic_chevron_right_white_24dp.png new file mode 100644 index 0000000000000000000000000000000000000000..b4f3c6d4c2a2afc9aa3677080a7ec573dac7e27f GIT binary patch literal 113 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*13r`ov5R22v2@bP0l+XkK{KX?Y literal 0 HcmV?d00001 diff --git a/sample/src/main/res/drawable-mdpi/ic_keyboard_arrow_right_white_24dp.png b/sample/src/main/res/drawable-mdpi/ic_keyboard_arrow_right_white_24dp.png deleted file mode 100644 index a00a250987eee7600bf1bf471e035725acb1c089..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 138 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iKu;IP5R22v2@y=H75l?;oFK3?m|Hpg7FH@Qi nKWFDWbuh}tBgl?x0|SFGd+6~)J-?Cnkb?;8!FYx* z8NV2c_cE5sZgVNvq$8-%#BMD5CX5lN_Q3V8*P_e*txA2qT#x5xC->|>TUzJ-xvFXX z{~G_Nr>Cdu$M38831<9X&#n`(;X~TPyn{`x*AHE6V&(2`XXO^FOHEwm6=xAX?d+kY ppLn=Ce;z&*vvXQ&HrVvz^WNAq$9(*;cwfvt z*@J~!)tS+m>1CQ*RAwCGyfdMbOnCUBivF>5sNVRQBIFaJ<}>4mQ8%2hTMq11H*W9PAo@e;k7hy~$2rUL@F^m<{vOd#UNM6)g~c{ps;SM_e~nt4 z(-nV#)9M|z!p%%CKG_NG{r*q=ci1leMh~HP#tU!HZz*~|r}z<{Vv9`Vfyhe=KwB9+ MUHx3vIVCg!0BGzwyZ`_I diff --git a/sample/src/main/res/drawable-xxhdpi/ic_chevron_left_white_48dp.png b/sample/src/main/res/drawable-xxhdpi/ic_chevron_left_white_48dp.png new file mode 100644 index 0000000000000000000000000000000000000000..42a4e219e51fd5b580e9b8207e470ca59f0dd26e GIT binary patch literal 242 zcmeAS@N?(olHy`uVBq!ia0vp^6F``Q1xWh(YZ(Knot`d^Ar-gYUhoucFc4tfz~wAq zT^c9H_U}%nlHyuMpb7}^$^LRtcgei|MK>0&coP`%O+%|%WU6h~DLL2F^XV5Suc`X- z;^JcWemPrQj0p;^T_T!6U$!suou~w6nz&zF=K*2QTKpnl350z%aEpf5IX8__0J0O6z`v!4Y8E$(&pTpN@>eagzod%Rdxy{2dc zE^>LfG9X`MQSmL!mo+PmFDxux8N9R9&8mIwomHEsEDB8zFM6S(I{jQ!(JP=)57gDp W=Xk zlly;YUXu*eJeb8Jx+wdQ1=At!`=RC97B|&61%cqN*Da0WM>(M@w0!STHO+!Ab}~bR;9J?n6v1p z=9EK)Ph%eN6r3xlvQ(b?poU+)-S~i|RH0ptlHPLXuJf4_Y%KIA@h?}iEbIV+7yeaD YJEW3&7S3+&0lJ#O)78&qol`;+06LLbwEzGB diff --git a/sample/src/main/res/drawable/toolbar_gradient.xml b/sample/src/main/res/drawable/toolbar_gradient.xml new file mode 100644 index 00000000..80c65ad2 --- /dev/null +++ b/sample/src/main/res/drawable/toolbar_gradient.xml @@ -0,0 +1,24 @@ + + + + + \ No newline at end of file diff --git a/sample/src/main/res/drawable/view_pager_tab_background.xml b/sample/src/main/res/drawable/view_pager_tab_background.xml deleted file mode 100644 index 693c2b42..00000000 --- a/sample/src/main/res/drawable/view_pager_tab_background.xml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_character_details.xml b/sample/src/main/res/layout/activity_character_details.xml index 7d5d1227..46e57895 100644 --- a/sample/src/main/res/layout/activity_character_details.xml +++ b/sample/src/main/res/layout/activity_character_details.xml @@ -14,7 +14,8 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - + android:orientation="vertical" + android:padding="@dimen/character_description_padding" + > - + - + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_comic_details.xml b/sample/src/main/res/layout/activity_comic_details.xml index aa141de4..8ba5e290 100644 --- a/sample/src/main/res/layout/activity_comic_details.xml +++ b/sample/src/main/res/layout/activity_comic_details.xml @@ -34,31 +34,40 @@ android:contentDescription="@string/comic_cover_content_description" /> - - + android:orientation="vertical" + android:padding="@dimen/comic_description_padding" + > - + - + + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index 63859944..c9602c78 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -16,16 +16,19 @@ --> - diff --git a/sample/src/main/res/layout/item_comic.xml b/sample/src/main/res/layout/item_comic.xml index 6de31dba..e186a5cf 100644 --- a/sample/src/main/res/layout/item_comic.xml +++ b/sample/src/main/res/layout/item_comic.xml @@ -42,7 +42,7 @@ android:layout_centerVertical="true" android:layout_marginRight="@dimen/comic_next_icon_margin_right" android:layout_marginEnd="@dimen/comic_next_icon_margin_right" - android:background="@drawable/ic_keyboard_arrow_right_white_24dp" + android:background="@drawable/ic_chevron_right_white_24dp" android:contentDescription="@string/comic_next_icon_content_description" /> diff --git a/sample/src/main/res/layout/toolbar.xml b/sample/src/main/res/layout/toolbar.xml new file mode 100644 index 00000000..27f0cc82 --- /dev/null +++ b/sample/src/main/res/layout/toolbar.xml @@ -0,0 +1,48 @@ + + + + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml index fb68fce8..9f7d9339 100644 --- a/sample/src/main/res/values/colors.xml +++ b/sample/src/main/res/values/colors.xml @@ -15,7 +15,11 @@ ~ limitations under the License. --> + #1D252D #2D353D + #FF1D252D + #001D252D + #FFFFFF #404B58 #00C8FF #FFFFFF diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml index 13832cba..3b7e6d3c 100644 --- a/sample/src/main/res/values/dimens.xml +++ b/sample/src/main/res/values/dimens.xml @@ -18,25 +18,29 @@ 40dp 38dp 50dp + 24sp + 56dp + 48dp + 8dp 50dp 10dp 14sp 10dp 24dp 1dp - 300dp - 14sp - 16dp + 350dp + 16sp + 20dp 8dp 50dp 10dp 14sp - 300dp + @dimen/comic_cover_height 24dp 10dp - 14sp - 16dp - 8dp + @dimen/comic_description_text_size + @dimen/comic_description_padding + @dimen/comic_description_margin_top 80dp 5dp diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index 5cb23637..ba78fbb6 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -16,6 +16,7 @@ --> Rosie + Go back Loading… Characters Comics diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml index 4fc31491..c27ebf83 100644 --- a/sample/src/main/res/values/styles.xml +++ b/sample/src/main/res/values/styles.xml @@ -16,28 +16,35 @@ --> - - - + + - - From e811d92d0d5aca3b0e13729020286ab563220085 Mon Sep 17 00:00:00 2001 From: Sergio Gutierrez Date: Fri, 11 Dec 2015 16:32:14 +0100 Subject: [PATCH 3/7] Add comics to comic details window --- sample/src/main/AndroidManifest.xml | 2 +- .../sample/comics/domain/model/Comic.java | 50 ++++++++++++++++ .../comics/domain/model/ComicSeries.java | 11 ++++ .../datasource/ComicSeriesApiDataSource.java | 37 ++++++++++++ .../activity/ComicSeriesDetailsActivity.java | 41 ++++++------- .../comics/view/renderer/ComicRenderer.java | 51 +++++++++++++++++ .../ComicSeriesDetailRendererBuilder.java | 46 +++++++++++++++ .../ComicSeriesHeaderDetailRenderer.java | 53 +++++++++++++++++ .../view/renderer/ComicSeriesRenderer.java | 2 +- .../viewmodel/ComicSeriesDetailViewModel.java | 20 +++++++ .../ComicSeriesDetailsViewModel.java | 31 +++------- .../ComicSeriesHeaderDetailViewModel.java | 57 +++++++++++++++++++ .../comics/view/viewmodel/ComicViewModel.java | 48 ++++++++++++++++ ...esToComicSeriesDetailsViewModelMapper.java | 49 ++++++++++++++-- sample/src/main/res/drawable/comic_border.xml | 28 +++++++++ .../layout/activity_comic_series_details.xml | 55 ++---------------- sample/src/main/res/layout/item_comic.xml | 42 ++++++++++++++ .../src/main/res/layout/item_comic_series.xml | 4 +- .../res/layout/item_comic_series_header.xml | 54 ++++++++++++++++++ sample/src/main/res/layout/item_load_more.xml | 4 +- sample/src/main/res/values/colors.xml | 6 +- sample/src/main/res/values/dimens.xml | 8 +++ sample/src/main/res/values/strings.xml | 3 +- sample/src/main/res/values/styles.xml | 25 ++++++-- 24 files changed, 616 insertions(+), 111 deletions(-) create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/Comic.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicRenderer.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesDetailRendererBuilder.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesHeaderDetailRenderer.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailViewModel.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesHeaderDetailViewModel.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicViewModel.java create mode 100644 sample/src/main/res/drawable/comic_border.xml create mode 100644 sample/src/main/res/layout/item_comic.xml create mode 100644 sample/src/main/res/layout/item_comic_series_header.xml diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index ceeda9e0..c86977b6 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -41,7 +41,7 @@ - + diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/Comic.java b/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/Comic.java new file mode 100644 index 00000000..e9bd7c46 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/Comic.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.domain.model; + +import com.karumi.rosie.repository.datasource.Identifiable; + +public class Comic implements Identifiable { + + private int key; + private String name; + private String thumbnailUrl; + + @Override public Integer getKey() { + return key; + } + + public void setKey(int key) { + this.key = key; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getThumbnailUrl() { + return thumbnailUrl; + } + + public void setThumbnailUrl(String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/ComicSeries.java b/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/ComicSeries.java index 756c4548..7526e688 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/ComicSeries.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/domain/model/ComicSeries.java @@ -17,6 +17,8 @@ package com.karumi.rosie.sample.comics.domain.model; import com.karumi.rosie.repository.datasource.Identifiable; +import java.util.ArrayList; +import java.util.List; public class ComicSeries implements Identifiable { @@ -27,6 +29,7 @@ public class ComicSeries implements Identifiable { private String coverUrl; private int releaseYear; private Rating rating; + private List comics = new ArrayList<>(); @Override public Integer getKey() { return key; @@ -84,6 +87,14 @@ public void setRating(Rating rating) { this.rating = rating; } + public List getComics() { + return comics; + } + + public void setComics(List comics) { + this.comics = comics; + } + public enum Rating { ALL_AGES, T, diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/repository/datasource/ComicSeriesApiDataSource.java b/sample/src/main/java/com/karumi/rosie/sample/comics/repository/datasource/ComicSeriesApiDataSource.java index 9522c9de..5f4d5973 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/repository/datasource/ComicSeriesApiDataSource.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/repository/datasource/ComicSeriesApiDataSource.java @@ -20,15 +20,20 @@ import com.karumi.rosie.repository.PaginatedCollection; import com.karumi.rosie.repository.datasource.EmptyReadableDataSource; import com.karumi.rosie.repository.datasource.paginated.PaginatedReadableDataSource; +import com.karumi.rosie.sample.comics.domain.model.Comic; import com.karumi.rosie.sample.comics.domain.model.ComicSeries; +import java.util.ArrayList; import java.util.Collection; import java.util.LinkedList; +import java.util.List; import java.util.Random; import javax.inject.Inject; public class ComicSeriesApiDataSource extends EmptyReadableDataSource implements PaginatedReadableDataSource { + private static final int MIN_NUMBER_OF_COMICS_PER_COMIC_SERIES = 9; + private static final int MAX_NUMBER_OF_COMICS_PER_COMIC_SERIES = 24; private static final int NUMBER_OF_COMIC_SERIES = 80; private static final int GUARDIANS_OF_INFINITY_KEY = 58086; private static final int VISION_KEY = 57309; @@ -112,6 +117,7 @@ private ComicSeries getComicSeries(int i) { + " life and death! THIS AIN’T KAYFABE, BROTHER! "); guardiansOfInfinity.setReleaseYear(2015); guardiansOfInfinity.setRating(ComicSeries.Rating.ALL_AGES); + guardiansOfInfinity.setComics(getComics(guardiansOfInfinity.getName())); return guardiansOfInfinity; } @@ -133,6 +139,7 @@ private ComicSeries getComicSeries(int i) { + " life and death! THIS AIN’T KAYFABE, BROTHER! "); vision.setReleaseYear(2015); vision.setRating(ComicSeries.Rating.T); + vision.setComics(getComics(vision.getName())); return vision; } @@ -154,6 +161,7 @@ private ComicSeries getComicSeries(int i) { + " life and death! THIS AIN’T KAYFABE, BROTHER! "); spidey.setReleaseYear(2015); spidey.setRating(ComicSeries.Rating.TEENS_AND_UP); + spidey.setComics(getComics(spidey.getName())); return spidey; } @@ -175,6 +183,7 @@ private ComicSeries getComicSeries(int i) { + " life and death! THIS AIN’T KAYFABE, BROTHER! "); redWolf.setReleaseYear(2015); redWolf.setRating(ComicSeries.Rating.EXPLICIT_CONTENT); + redWolf.setComics(getComics(redWolf.getName())); return redWolf; } @@ -196,9 +205,37 @@ private ComicSeries getComicSeries(int i) { + " life and death! THIS AIN’T KAYFABE, BROTHER! "); nova.setReleaseYear(2015); nova.setRating(ComicSeries.Rating.PARENTAL_ADVISORY); + nova.setComics(getComics(nova.getName())); return nova; } + @NonNull private List getComics(String comicSeriesName) { + List comics = new ArrayList<>(); + + String[] allComicThumbnailUrls = { + "http://x.annihil.us/u/prod/marvel/i/mg/6/c0/5554eab0886b8/detail.jpg", + "http://i.annihil.us/u/prod/marvel/i/mg/c/a0/553514e108202/detail.jpg", + "http://i.annihil.us/u/prod/marvel/i/mg/6/30/5503446dc71bf/detail.jpg", + "http://i.annihil.us/u/prod/marvel/i/mg/f/10/54cfb2f5f0b2e/detail.jpg", + "http://x.annihil.us/u/prod/marvel/i/mg/4/20/54b55c72b7896/detail.jpg", + "http://i.annihil.us/u/prod/marvel/i/mg/4/00/5491a1de66768/detail.jpg", + "http://x.annihil.us/u/prod/marvel/i/mg/6/c0/5464eabe99180/detail.jpg", + "http://x.annihil.us/u/prod/marvel/i/mg/3/00/55b242ad84037/detail.jpg" + }; + + int numberOfComics = MIN_NUMBER_OF_COMICS_PER_COMIC_SERIES + RANDOM.nextInt( + MAX_NUMBER_OF_COMICS_PER_COMIC_SERIES - MIN_NUMBER_OF_COMICS_PER_COMIC_SERIES + 1); + for (int i = 0; i < numberOfComics; i++) { + Comic comic = new Comic(); + comic.setKey(i); + comic.setName(comicSeriesName + " #" + (i + 1)); + comic.setThumbnailUrl(allComicThumbnailUrls[RANDOM.nextInt(allComicThumbnailUrls.length)]); + comics.add(comic); + } + + return comics; + } + private void fakeDelay() { try { Thread.sleep(SLEEP_TIME_IN_MILLISECONDS); diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicSeriesDetailsActivity.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicSeriesDetailsActivity.java index cf14e55f..edacb818 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicSeriesDetailsActivity.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/activity/ComicSeriesDetailsActivity.java @@ -21,20 +21,22 @@ import android.os.Bundle; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; import android.view.View; -import android.widget.ImageView; import android.widget.TextView; import butterknife.Bind; import butterknife.OnClick; import com.karumi.rosie.sample.R; import com.karumi.rosie.sample.comics.ComicsModule; import com.karumi.rosie.sample.comics.view.presenter.ComicSeriesDetailsPresenter; +import com.karumi.rosie.sample.comics.view.renderer.ComicSeriesDetailRendererBuilder; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailViewModel; import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailsViewModel; -import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesViewModel; import com.karumi.rosie.view.Presenter; import com.karumi.rosie.view.RosieActivity; +import com.pedrogomez.renderers.ListAdapteeCollection; import com.pedrogomez.renderers.RVRendererAdapter; -import com.squareup.picasso.Picasso; +import com.pedrogomez.renderers.RendererBuilder; import com.victor.loading.rotate.RotateLoading; import java.util.Arrays; import java.util.List; @@ -48,16 +50,12 @@ public class ComicSeriesDetailsActivity extends RosieActivity private static final int NUMBER_OF_COLUMNS = 3; @Bind(R.id.tv_toolbar_title) TextView toolbarTitleView; - @Bind(R.id.ll_comic_detail) View comicSeriesView; - @Bind(R.id.iv_cover) ImageView coverView; - @Bind(R.id.tv_rating) TextView ratingView; - @Bind(R.id.tv_description) TextView descriptionView; @Bind(R.id.loading) RotateLoading loadingView; @Bind(R.id.rv_comics) RecyclerView comicsView; @Inject @Presenter ComicSeriesDetailsPresenter presenter; - private RVRendererAdapter comicSeriesAdapter; + private RVRendererAdapter comicDetailsAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -85,16 +83,15 @@ public class ComicSeriesDetailsActivity extends RosieActivity } @Override public void hideComicSeriesDetails() { - comicSeriesView.setVisibility(View.GONE); + comicsView.setVisibility(View.GONE); } @Override public void showComicSeriesDetails(ComicSeriesDetailsViewModel comicSeries) { - Picasso.with(this).load(comicSeries.getCoverUrl()).fit().centerCrop().into(coverView); - String rating = getString(comicSeries.getRatingNameResourceId()); toolbarTitleView.setText(comicSeries.getTitle()); - ratingView.setText(getString(R.string.marvel_rating_text, rating)); - descriptionView.setText(comicSeries.getDescription()); - comicSeriesView.setVisibility(View.VISIBLE); + comicsView.setVisibility(View.VISIBLE); + comicDetailsAdapter.clear(); + comicDetailsAdapter.addAll(comicSeries.getComicSeriesDetailViewModels()); + comicDetailsAdapter.notifyDataSetChanged(); } @Override public void close() { @@ -113,16 +110,22 @@ public static void open(Context context, int comicSeriesKey) { private void initializeComicsView() { GridLayoutManager layoutManager = new GridLayoutManager(this, NUMBER_OF_COLUMNS); + layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { + @Override public int getSpanSize(int position) { + return position == 0 ? NUMBER_OF_COLUMNS : 1; + } + }); comicsView.setHasFixedSize(true); comicsView.setLayoutManager(layoutManager); initializeAdapter(); - comicsView.setAdapter(comicSeriesAdapter); + comicsView.setAdapter(comicDetailsAdapter); } private void initializeAdapter() { - //LayoutInflater layoutInflater = LayoutInflater.from(this); - //RendererBuilder rendererBuilder = new ComicSeriesRendererBuilder(presenter); - //comicsCollection = new ComicsSeriesAdapteeCollection(); - //comicSeriesAdapter = new RVRendererAdapter<>(layoutInflater, rendererBuilder, comicsCollection); + LayoutInflater layoutInflater = LayoutInflater.from(this); + RendererBuilder rendererBuilder = + new ComicSeriesDetailRendererBuilder(); + comicDetailsAdapter = new RVRendererAdapter<>(layoutInflater, rendererBuilder, + new ListAdapteeCollection()); } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicRenderer.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicRenderer.java new file mode 100644 index 00000000..462753cb --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicRenderer.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.view.renderer; + +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import butterknife.Bind; +import com.karumi.rosie.renderer.RosieRenderer; +import com.karumi.rosie.sample.R; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailViewModel; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicViewModel; +import com.squareup.picasso.Picasso; + +public class ComicRenderer extends RosieRenderer { + + @Bind(R.id.iv_thumbnail) ImageView thumbnailView; + @Bind(R.id.tv_title) TextView titleView; + + @Override public void render() { + super.render(); + + ComicViewModel comic = (ComicViewModel) getContent(); + titleView.setText(comic.getTitle()); + Picasso.with(getRootView().getContext()) + .load(comic.getThumbnailUrl()) + .fit() + .centerCrop() + .into(thumbnailView); + } + + @Override protected View inflate(LayoutInflater inflater, ViewGroup parent) { + return inflater.inflate(R.layout.item_comic, parent, false); + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesDetailRendererBuilder.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesDetailRendererBuilder.java new file mode 100644 index 00000000..4bf3036f --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesDetailRendererBuilder.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.view.renderer; + +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailViewModel; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesHeaderDetailViewModel; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicViewModel; +import com.pedrogomez.renderers.Renderer; +import com.pedrogomez.renderers.RendererBuilder; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class ComicSeriesDetailRendererBuilder extends RendererBuilder { + + private Map rendererMapping = new HashMap<>(); + + public ComicSeriesDetailRendererBuilder() { + List> prototypes = new LinkedList<>(); + prototypes.add(new ComicRenderer()); + rendererMapping.put(ComicViewModel.class, ComicRenderer.class); + prototypes.add(new ComicSeriesHeaderDetailRenderer()); + rendererMapping.put(ComicSeriesHeaderDetailViewModel.class, + ComicSeriesHeaderDetailRenderer.class); + setPrototypes(prototypes); + } + + @Override protected Class getPrototypeClass(ComicSeriesDetailViewModel content) { + return rendererMapping.get(content.getClass()); + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesHeaderDetailRenderer.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesHeaderDetailRenderer.java new file mode 100644 index 00000000..64c3eca9 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesHeaderDetailRenderer.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.view.renderer; + +import android.content.Context; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ImageView; +import android.widget.TextView; +import butterknife.Bind; +import com.karumi.rosie.renderer.RosieRenderer; +import com.karumi.rosie.sample.R; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailViewModel; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesHeaderDetailViewModel; +import com.squareup.picasso.Picasso; + +public class ComicSeriesHeaderDetailRenderer extends RosieRenderer { + + @Bind(R.id.iv_cover) ImageView coverView; + @Bind(R.id.tv_rating) TextView ratingView; + @Bind(R.id.tv_description) TextView descriptionView; + + @Override public void render() { + super.render(); + + Context context = getRootView().getContext(); + ComicSeriesHeaderDetailViewModel comicSeries = (ComicSeriesHeaderDetailViewModel) getContent(); + + Picasso.with(context).load(comicSeries.getCoverUrl()).fit().centerCrop().into(coverView); + String rating = context.getString(comicSeries.getRatingNameResourceId()); + ratingView.setText(context.getString(R.string.marvel_rating_text, rating)); + descriptionView.setText(comicSeries.getDescription()); + } + + @Override protected View inflate(LayoutInflater inflater, ViewGroup parent) { + return inflater.inflate(R.layout.item_comic_series_header, parent, false); + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesRenderer.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesRenderer.java index 602c5557..35711cc2 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesRenderer.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/renderer/ComicSeriesRenderer.java @@ -31,7 +31,7 @@ public class ComicSeriesRenderer extends RosieRenderer { private final ComicsSeriesPresenter presenter; - @Bind(R.id.tv_comic_name) TextView nameView; + @Bind(R.id.tv_comic_series_name) TextView nameView; public ComicSeriesRenderer(ComicsSeriesPresenter presenter) { this.presenter = presenter; diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailViewModel.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailViewModel.java new file mode 100644 index 00000000..e0bbb2ac --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailViewModel.java @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.view.viewmodel; + +public interface ComicSeriesDetailViewModel { +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailsViewModel.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailsViewModel.java index d51a8e9e..e2709c67 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailsViewModel.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesDetailsViewModel.java @@ -16,12 +16,12 @@ package com.karumi.rosie.sample.comics.view.viewmodel; +import java.util.List; + public class ComicSeriesDetailsViewModel { private String title; - private String coverUrl; - private String description; - private int ratingNameResourceId; + private List comicSeriesDetailViewModels; public String getTitle() { return title; @@ -31,27 +31,12 @@ public void setTitle(String title) { this.title = title; } - public String getCoverUrl() { - return coverUrl; - } - - public void setCoverUrl(String coverUrl) { - this.coverUrl = coverUrl; - } - - public String getDescription() { - return description; - } - - public void setDescription(String description) { - this.description = description; - } - - public int getRatingNameResourceId() { - return ratingNameResourceId; + public List getComicSeriesDetailViewModels() { + return comicSeriesDetailViewModels; } - public void setRatingNameResourceId(int ratingNameResourceId) { - this.ratingNameResourceId = ratingNameResourceId; + public void setComicSeriesDetailViewModels( + List comicSeriesDetailViewModels) { + this.comicSeriesDetailViewModels = comicSeriesDetailViewModels; } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesHeaderDetailViewModel.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesHeaderDetailViewModel.java new file mode 100644 index 00000000..2d32dbe5 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicSeriesHeaderDetailViewModel.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.view.viewmodel; + +public class ComicSeriesHeaderDetailViewModel implements ComicSeriesDetailViewModel { + + private String title; + private String coverUrl; + private String description; + private int ratingNameResourceId; + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getCoverUrl() { + return coverUrl; + } + + public void setCoverUrl(String coverUrl) { + this.coverUrl = coverUrl; + } + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + public int getRatingNameResourceId() { + return ratingNameResourceId; + } + + public void setRatingNameResourceId(int ratingNameResourceId) { + this.ratingNameResourceId = ratingNameResourceId; + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicViewModel.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicViewModel.java new file mode 100644 index 00000000..e3ff3df4 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/ComicViewModel.java @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.comics.view.viewmodel; + +public class ComicViewModel implements ComicSeriesDetailViewModel { + + private int key; + private String title; + private String thumbnailUrl; + + public int getKey() { + return key; + } + + public void setKey(int key) { + this.key = key; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getThumbnailUrl() { + return thumbnailUrl; + } + + public void setThumbnailUrl(String thumbnailUrl) { + this.thumbnailUrl = thumbnailUrl; + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/mapper/ComicSeriesToComicSeriesDetailsViewModelMapper.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/mapper/ComicSeriesToComicSeriesDetailsViewModelMapper.java index 20152031..071078ad 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/mapper/ComicSeriesToComicSeriesDetailsViewModelMapper.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/viewmodel/mapper/ComicSeriesToComicSeriesDetailsViewModelMapper.java @@ -17,8 +17,15 @@ package com.karumi.rosie.sample.comics.view.viewmodel.mapper; import com.karumi.rosie.sample.R; +import com.karumi.rosie.sample.comics.domain.model.Comic; import com.karumi.rosie.sample.comics.domain.model.ComicSeries; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailViewModel; import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesDetailsViewModel; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicSeriesHeaderDetailViewModel; +import com.karumi.rosie.sample.comics.view.viewmodel.ComicViewModel; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import javax.inject.Inject; public class ComicSeriesToComicSeriesDetailsViewModelMapper { @@ -30,16 +37,32 @@ public ComicSeriesDetailsViewModel mapComicSeriesToComicSeriesDetailsViewModel( ComicSeries comicSeries) { ComicSeriesDetailsViewModel comicSeriesDetailsViewModel = new ComicSeriesDetailsViewModel(); - comicSeriesDetailsViewModel.setTitle( - comicSeries.getName() + " (" + comicSeries.getReleaseYear() + ") #" + comicSeries.getNumber()); - comicSeriesDetailsViewModel.setCoverUrl(comicSeries.getCoverUrl()); - comicSeriesDetailsViewModel.setDescription(comicSeries.getDescription()); - comicSeriesDetailsViewModel.setRatingNameResourceId(getRatingNameResourceId(comicSeries.getRating())); + comicSeriesDetailsViewModel.setTitle(comicSeries.getName()); + List comicSeriesDetailViewModels = new LinkedList<>(); + comicSeriesDetailViewModels.add(mapComicSeriesToComicSeriesHeaderDetailViewModel(comicSeries)); + comicSeriesDetailViewModels.addAll(mapComicsToComicViewModels(comicSeries.getComics())); + comicSeriesDetailsViewModel.setComicSeriesDetailViewModels(comicSeriesDetailViewModels); return comicSeriesDetailsViewModel; } - private int getRatingNameResourceId(ComicSeries.Rating rating) { + private ComicSeriesHeaderDetailViewModel mapComicSeriesToComicSeriesHeaderDetailViewModel( + ComicSeries comicSeries) { + ComicSeriesHeaderDetailViewModel comicSeriesHeaderDetailViewModel = + new ComicSeriesHeaderDetailViewModel(); + + comicSeriesHeaderDetailViewModel.setTitle( + comicSeries.getName() + " (" + comicSeries.getReleaseYear() + ") #" + + comicSeries.getNumber()); + comicSeriesHeaderDetailViewModel.setCoverUrl(comicSeries.getCoverUrl()); + comicSeriesHeaderDetailViewModel.setDescription(comicSeries.getDescription()); + comicSeriesHeaderDetailViewModel.setRatingNameResourceId( + mapRatingToRatingNameResourceId(comicSeries.getRating())); + + return comicSeriesHeaderDetailViewModel; + } + + private int mapRatingToRatingNameResourceId(ComicSeries.Rating rating) { int ratingNameResourceId; switch (rating) { case ALL_AGES: @@ -62,4 +85,18 @@ private int getRatingNameResourceId(ComicSeries.Rating rating) { return ratingNameResourceId; } + + private List mapComicsToComicViewModels(List comics) { + List comicViewModels = new ArrayList<>(); + + for (Comic comic : comics) { + ComicViewModel comicViewModel = new ComicViewModel(); + comicViewModel.setKey(comic.getKey()); + comicViewModel.setTitle(comic.getName()); + comicViewModel.setThumbnailUrl(comic.getThumbnailUrl()); + comicViewModels.add(comicViewModel); + } + + return comicViewModels; + } } diff --git a/sample/src/main/res/drawable/comic_border.xml b/sample/src/main/res/drawable/comic_border.xml new file mode 100644 index 00000000..cf756267 --- /dev/null +++ b/sample/src/main/res/drawable/comic_border.xml @@ -0,0 +1,28 @@ + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/layout/activity_comic_series_details.xml b/sample/src/main/res/layout/activity_comic_series_details.xml index 2d49da66..e3a6be83 100644 --- a/sample/src/main/res/layout/activity_comic_series_details.xml +++ b/sample/src/main/res/layout/activity_comic_series_details.xml @@ -20,58 +20,11 @@ android:background="@color/main_background" > - - - - - - - - - - - - - - - - - - - + android:layout_height="wrap_content" + /> diff --git a/sample/src/main/res/layout/item_comic.xml b/sample/src/main/res/layout/item_comic.xml new file mode 100644 index 00000000..83e92202 --- /dev/null +++ b/sample/src/main/res/layout/item_comic.xml @@ -0,0 +1,42 @@ + + + + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/layout/item_comic_series.xml b/sample/src/main/res/layout/item_comic_series.xml index 0c4bef5b..01992643 100644 --- a/sample/src/main/res/layout/item_comic_series.xml +++ b/sample/src/main/res/layout/item_comic_series.xml @@ -19,12 +19,12 @@ xmlns:tools="http://schemas.android.com/tools" android:id="@+id/ll_root" android:layout_width="match_parent" - android:layout_height="@dimen/comic_height" + android:layout_height="@dimen/comic_series_height" android:background="@color/comic_series_item_background" > + + + + + + + + + + + + + + \ No newline at end of file diff --git a/sample/src/main/res/layout/item_load_more.xml b/sample/src/main/res/layout/item_load_more.xml index bf6f70e1..7471162e 100644 --- a/sample/src/main/res/layout/item_load_more.xml +++ b/sample/src/main/res/layout/item_load_more.xml @@ -18,7 +18,7 @@ android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="@android:color/holo_blue_dark" + android:background="@color/load_more_background" > \ No newline at end of file diff --git a/sample/src/main/res/values/colors.xml b/sample/src/main/res/values/colors.xml index 35c24f3e..48dc0886 100644 --- a/sample/src/main/res/values/colors.xml +++ b/sample/src/main/res/values/colors.xml @@ -19,17 +19,21 @@ #2D353D #FF1D252D #001D252D - #FFFFFF + #FFFFFF #404B58 #00C8FF #FFFFFF #2D353D #EEEEEE #EEEEEE + #EEEEEE + #404B58 #2D353D @color/view_pager_tab_background #EEEEEE @color/comic_series_item_background #EEEEEE + @color/character_item_background + @android:color/white #FFFFFF diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml index 810db752..eafa5f90 100644 --- a/sample/src/main/res/values/dimens.xml +++ b/sample/src/main/res/values/dimens.xml @@ -32,6 +32,12 @@ 16sp 20dp 8dp + 8dp + 10dp + 1dp + 180dp + 6dp + 12sp 50dp 10dp 14sp @@ -43,4 +49,6 @@ @dimen/comic_series_description_margin_top 80dp 5dp + 14sp + 14dp diff --git a/sample/src/main/res/values/strings.xml b/sample/src/main/res/values/strings.xml index eb32c13b..74d670ad 100644 --- a/sample/src/main/res/values/strings.xml +++ b/sample/src/main/res/values/strings.xml @@ -27,7 +27,8 @@ Parental Advisory Max: Explicit Content See comic series details - Comic cover + Comic series cover + Comic thumbnail See character details Character thumbnail diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml index 104913f4..2018be6f 100644 --- a/sample/src/main/res/values/styles.xml +++ b/sample/src/main/res/values/styles.xml @@ -16,15 +16,18 @@ --> - - - + + + From c19e5c9f647370f78319c8441141c43d85e39a1a Mon Sep 17 00:00:00 2001 From: Sergio Gutierrez Date: Tue, 15 Dec 2015 10:47:29 +0100 Subject: [PATCH 4/7] Fix minor naming issues --- sample/src/main/AndroidManifest.xml | 4 ++-- .../view/activity/CharacterDetailsActivity.java | 4 +++- .../sample/comics/view/fragment/ComicSeriesFragment.java | 1 + sample/src/main/res/drawable/comic_border.xml | 8 ++++---- sample/src/main/res/values/dimens.xml | 1 + sample/src/main/res/values/styles.xml | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/sample/src/main/AndroidManifest.xml b/sample/src/main/AndroidManifest.xml index c86977b6..d9aa7bc9 100644 --- a/sample/src/main/AndroidManifest.xml +++ b/sample/src/main/AndroidManifest.xml @@ -26,12 +26,12 @@ android:allowBackup="true" android:icon="@mipmap/ic_logo_karumi" android:label="@string/app_name" - android:theme="@style/SampleStyle" + android:theme="@style/SampleTheme" > diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java b/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java index c984cce6..71e9ef34 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/view/activity/CharacterDetailsActivity.java @@ -83,7 +83,9 @@ public class CharacterDetailsActivity extends RosieActivity characterDetailView.setVisibility(View.VISIBLE); toolbarTitleView.setText(character.getName()); Picasso.with(this) - .load(character.getHeaderImage()).fit().centerCrop() + .load(character.getHeaderImage()) + .fit() + .centerCrop() .into(characterHeaderView); characterNameView.setText(character.getName()); characterDescriptionView.setText(character.getDescription()); diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/view/fragment/ComicSeriesFragment.java b/sample/src/main/java/com/karumi/rosie/sample/comics/view/fragment/ComicSeriesFragment.java index 60bbe45a..519e77a4 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/view/fragment/ComicSeriesFragment.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/view/fragment/ComicSeriesFragment.java @@ -82,6 +82,7 @@ public class ComicSeriesFragment extends RosieFragment implements ComicsSeriesPr } @Override public void showComicSeries(List comicSeries) { + comicSeriesAdapter.clear(); comicSeriesAdapter.addAll(comicSeries); comicSeriesAdapter.notifyDataSetChanged(); comicSeriesView.setVisibility(View.VISIBLE); diff --git a/sample/src/main/res/drawable/comic_border.xml b/sample/src/main/res/drawable/comic_border.xml index cf756267..afc4e4d7 100644 --- a/sample/src/main/res/drawable/comic_border.xml +++ b/sample/src/main/res/drawable/comic_border.xml @@ -20,9 +20,9 @@ android:color="@color/comic_thumbnail_border" /> \ No newline at end of file diff --git a/sample/src/main/res/values/dimens.xml b/sample/src/main/res/values/dimens.xml index eafa5f90..9eb12fcb 100644 --- a/sample/src/main/res/values/dimens.xml +++ b/sample/src/main/res/values/dimens.xml @@ -38,6 +38,7 @@ 180dp 6dp 12sp + 1dp 50dp 10dp 14sp diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml index 2018be6f..63882d25 100644 --- a/sample/src/main/res/values/styles.xml +++ b/sample/src/main/res/values/styles.xml @@ -16,7 +16,7 @@ --> - From bf3eaa362e3b155b572765230591a52e74c533db Mon Sep 17 00:00:00 2001 From: Jorge J Barroso Date: Fri, 18 Dec 2015 16:21:31 +0100 Subject: [PATCH 5/7] Add marvel api client and prepare rosie for that. --- .gitignore | 3 +- .../repository/PaginatedRosieRepository.java | 13 +- .../rosie/repository/RosieRepository.java | 32 ++-- .../datasource/EmptyCacheDataSource.java | 12 +- .../datasource/EmptyReadableDataSource.java | 4 +- .../datasource/ReadableDataSource.java | 4 +- .../datasource/WriteableDataSource.java | 8 +- .../EmptyPaginatedCacheDataSource.java | 6 +- .../PaginatedReadableDataSource.java | 2 +- .../PaginatedWriteableDataSource.java | 4 +- .../PaginatedRosieRepositoryTest.java | 4 +- .../rosie/repository/RosieRepositoryTest.java | 21 ++- sample/build.gradle | 31 ++++ .../rosie/sample/base/mapper/Mapper.java | 41 +++++ .../domain/usecase/GetCharacterDetails.java | 2 +- .../CharacterDataSourceFactory.java | 46 +++++ .../repository/CharactersRepository.java | 10 +- .../datasource/CharacterDataSource.java | 25 +++ .../datasource/CharactersApiDataSource.java | 141 +++------------ .../datasource/CharactersFakeDataSource.java | 163 ++++++++++++++++++ .../mapper/MapperCharacterToCharacterDto.java | 39 +++++ .../domain/usecase/GetComicSeriesDetails.java | 2 +- .../main/view/activity/MainActivity.java | 24 ++- .../view/presenter/FakeDataPresenter.java | 44 +++++ sample/src/main/res/layout/activity_main.xml | 7 + sample/src/main/res/values/strings.xml | 3 + sample/src/main/res/values/styles.xml | 7 + 27 files changed, 520 insertions(+), 178 deletions(-) create mode 100644 sample/src/main/java/com/karumi/rosie/sample/base/mapper/Mapper.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharacterDataSourceFactory.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharacterDataSource.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersFakeDataSource.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/mapper/MapperCharacterToCharacterDto.java create mode 100644 sample/src/main/java/com/karumi/rosie/sample/main/view/presenter/FakeDataPresenter.java diff --git a/.gitignore b/.gitignore index 74c68661..261dea50 100644 --- a/.gitignore +++ b/.gitignore @@ -33,4 +33,5 @@ target .DS_Store Thumbs.db *.swp -*.bak \ No newline at end of file +*.bak +marvel.properties diff --git a/rosie/src/main/java/com/karumi/rosie/repository/PaginatedRosieRepository.java b/rosie/src/main/java/com/karumi/rosie/repository/PaginatedRosieRepository.java index 6538dca6..4e03e2de 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/PaginatedRosieRepository.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/PaginatedRosieRepository.java @@ -51,7 +51,7 @@ protected final > void addPaginatedCach * @param offset Index of the first item to be retrieved * @param limit Number of elements that will be retrieved */ - public PaginatedCollection getPage(int offset, int limit) { + public PaginatedCollection getPage(int offset, int limit) throws Exception { return getPage(offset, limit, ReadPolicy.READ_ALL); } @@ -61,7 +61,7 @@ public PaginatedCollection getPage(int offset, int limit) { * @param limit Number of elements that will be retrieved * @param policy Specifies how the value is going to be retrieved. */ - public PaginatedCollection getPage(int offset, int limit, ReadPolicy policy) { + public PaginatedCollection getPage(int offset, int limit, ReadPolicy policy) throws Exception { PaginatedCollection values = null; if (policy.useCache()) { @@ -79,7 +79,8 @@ public PaginatedCollection getPage(int offset, int limit, ReadPolicy policy) return values; } - protected PaginatedCollection getPaginatedValuesFromCaches(int offset, int limit) { + protected PaginatedCollection getPaginatedValuesFromCaches(int offset, int limit) + throws Exception { PaginatedCollection values = null; for (PaginatedCacheDataSource cacheDataSource : paginatedCacheDataSources) { @@ -98,7 +99,8 @@ protected PaginatedCollection getPaginatedValuesFromCaches(int offset, int li return values; } - protected PaginatedCollection getPaginatedValuesFromReadables(int offset, int limit) { + protected PaginatedCollection getPaginatedValuesFromReadables(int offset, int limit) + throws Exception { PaginatedCollection values = null; for (PaginatedReadableDataSource readable : paginatedReadableDataSources) { @@ -112,7 +114,8 @@ protected PaginatedCollection getPaginatedValuesFromReadables(int offset, int return values; } - protected void populatePaginatedCaches(int offset, int limit, PaginatedCollection values) { + protected void populatePaginatedCaches(int offset, int limit, PaginatedCollection values) + throws Exception { for (PaginatedCacheDataSource cacheDataSource : paginatedCacheDataSources) { cacheDataSource.addOrUpdatePage(offset, limit, values.getItems(), values.hasMore()); } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/RosieRepository.java b/rosie/src/main/java/com/karumi/rosie/repository/RosieRepository.java index f7e19722..6a05822f 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/RosieRepository.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/RosieRepository.java @@ -61,7 +61,7 @@ public class RosieRepository> /** * {@link ReadableDataSource#getByKey(Object)} */ - @Override public V getByKey(K key) { + @Override public V getByKey(K key) throws Exception { return getByKey(key, ReadPolicy.READ_ALL); } @@ -70,7 +70,7 @@ public class RosieRepository> * * @param policy Specifies how the value is going to be retrieved. */ - public V getByKey(K key, ReadPolicy policy) { + public V getByKey(K key, ReadPolicy policy) throws Exception { validateKey(key); V value = null; @@ -93,7 +93,7 @@ public V getByKey(K key, ReadPolicy policy) { /** * {@link ReadableDataSource#getAll()} */ - @Override public Collection getAll() { + @Override public Collection getAll() throws Exception { return getAll(ReadPolicy.READ_ALL); } @@ -102,7 +102,7 @@ public V getByKey(K key, ReadPolicy policy) { * * @param policy Specifies how the value is going to be retrieved. */ - public Collection getAll(ReadPolicy policy) { + public Collection getAll(ReadPolicy policy) throws Exception { Collection values = null; if (policy.useCache()) { @@ -123,7 +123,7 @@ public Collection getAll(ReadPolicy policy) { /** * {@link WriteableDataSource#addOrUpdate(Identifiable)} */ - @Override public V addOrUpdate(V value) { + @Override public V addOrUpdate(V value) throws Exception { return addOrUpdate(value, WritePolicy.WRITE_ALL); } @@ -132,7 +132,7 @@ public Collection getAll(ReadPolicy policy) { * * @param policy Specifies how the value is going to be stored. */ - public V addOrUpdate(V value, WritePolicy policy) { + public V addOrUpdate(V value, WritePolicy policy) throws Exception { validateValue(value); V updatedValue = null; @@ -155,11 +155,11 @@ public V addOrUpdate(V value, WritePolicy policy) { /** * {@link WriteableDataSource#addOrUpdateAll(Collection)} */ - @Override public Collection addOrUpdateAll(Collection values) { + @Override public Collection addOrUpdateAll(Collection values) throws Exception { return addOrUpdateAll(values, WritePolicy.WRITE_ALL); } - public Collection addOrUpdateAll(Collection values, WritePolicy policy) { + public Collection addOrUpdateAll(Collection values, WritePolicy policy) throws Exception { validateValues(values); Collection updatedValues = null; @@ -182,7 +182,7 @@ public Collection addOrUpdateAll(Collection values, WritePolicy policy) { /** * {@link WriteableDataSource#deleteByKey(Object)} */ - @Override public void deleteByKey(K key) { + @Override public void deleteByKey(K key) throws Exception { for (WriteableDataSource writeableDataSource : writeableDataSources) { writeableDataSource.deleteByKey(key); } @@ -195,7 +195,7 @@ public Collection addOrUpdateAll(Collection values, WritePolicy policy) { /** * {@link WriteableDataSource#deleteAll()} */ - @Override public void deleteAll() { + @Override public void deleteAll() throws Exception { for (WriteableDataSource writeableDataSource : writeableDataSources) { writeableDataSource.deleteAll(); } @@ -205,7 +205,7 @@ public Collection addOrUpdateAll(Collection values, WritePolicy policy) { } } - private V getValueFromCaches(K id) { + private V getValueFromCaches(K id) throws Exception { V value = null; for (CacheDataSource cacheDataSource : cacheDataSources) { @@ -224,7 +224,7 @@ private V getValueFromCaches(K id) { return value; } - private Collection getValuesFromCaches() { + private Collection getValuesFromCaches() throws Exception { Collection values = null; for (CacheDataSource cacheDataSource : cacheDataSources) { @@ -243,7 +243,7 @@ private Collection getValuesFromCaches() { return values; } - private V getValueFromReadables(K key) { + private V getValueFromReadables(K key) throws Exception { V value = null; for (ReadableDataSource readableDataSource : readableDataSources) { @@ -257,7 +257,7 @@ private V getValueFromReadables(K key) { return value; } - protected Collection getValuesFromReadables() { + protected Collection getValuesFromReadables() throws Exception { Collection values = null; for (ReadableDataSource readableDataSource : readableDataSources) { @@ -271,13 +271,13 @@ protected Collection getValuesFromReadables() { return values; } - private void populateCaches(V value) { + private void populateCaches(V value) throws Exception { for (CacheDataSource cacheDataSource : cacheDataSources) { cacheDataSource.addOrUpdate(value); } } - protected void populateCaches(Collection values) { + protected void populateCaches(Collection values) throws Exception { for (CacheDataSource cacheDataSource : cacheDataSources) { cacheDataSource.addOrUpdateAll(values); } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyCacheDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyCacheDataSource.java index c9347956..fea29ee8 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyCacheDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyCacheDataSource.java @@ -23,27 +23,27 @@ */ public class EmptyCacheDataSource> implements CacheDataSource { - @Override public V getByKey(K key) { + @Override public V getByKey(K key) throws Exception { return null; } - @Override public Collection getAll() { + @Override public Collection getAll() throws Exception { return null; } - @Override public V addOrUpdate(V value) { + @Override public V addOrUpdate(V value) throws Exception { return null; } - @Override public Collection addOrUpdateAll(Collection values) { + @Override public Collection addOrUpdateAll(Collection values) throws Exception { return null; } - @Override public void deleteByKey(K key) { + @Override public void deleteByKey(K key) throws Exception { } - @Override public void deleteAll() { + @Override public void deleteAll() throws Exception { } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyReadableDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyReadableDataSource.java index a2986680..dec2e3f8 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyReadableDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/EmptyReadableDataSource.java @@ -24,11 +24,11 @@ */ public class EmptyReadableDataSource implements ReadableDataSource { - @Override public V getByKey(K key) { + @Override public V getByKey(K key) throws Exception { return null; } - @Override public Collection getAll() { + @Override public Collection getAll() throws Exception { return null; } } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/ReadableDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/ReadableDataSource.java index 95bac3e8..d7d498ee 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/ReadableDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/ReadableDataSource.java @@ -32,7 +32,7 @@ public interface ReadableDataSource { * @param key The key that uniquely identifies the requested value. * @return The value associated to the provided key or null if there is not any. */ - V getByKey(K key); + V getByKey(K key) throws Exception; /** * Returns all the values available in the data source or null if the operation does not make @@ -40,5 +40,5 @@ public interface ReadableDataSource { * * @return A collection of values or null if the operation is not implemented by this data source. */ - Collection getAll(); + Collection getAll() throws Exception; } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/WriteableDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/WriteableDataSource.java index 19f57857..b39b495d 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/WriteableDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/WriteableDataSource.java @@ -31,7 +31,7 @@ public interface WriteableDataSource> { * @param value The value to be persisted. * @return The value after its addition or update. */ - V addOrUpdate(V value); + V addOrUpdate(V value) throws Exception; /** * Add or updates all the provided values into this data source. @@ -39,17 +39,17 @@ public interface WriteableDataSource> { * @param values A collection of values to be added or persisted. * @return The values that has been persisted. */ - Collection addOrUpdateAll(Collection values); + Collection addOrUpdateAll(Collection values) throws Exception; /** * Deletes a value given its associated key. * * @param key The key that uniquely identifies the value to be deleted. */ - void deleteByKey(K key); + void deleteByKey(K key) throws Exception; /** * Delete all the values stored in this data source. */ - void deleteAll(); + void deleteAll() throws Exception; } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/EmptyPaginatedCacheDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/EmptyPaginatedCacheDataSource.java index 26130499..5ebee2da 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/EmptyPaginatedCacheDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/EmptyPaginatedCacheDataSource.java @@ -27,17 +27,17 @@ public class EmptyPaginatedCacheDataSource> return false; } - @Override public PaginatedCollection getPage(int offset, int limit) { + @Override public PaginatedCollection getPage(int offset, int limit) throws Exception { return null; } @Override public PaginatedCollection addOrUpdatePage(int offset, int limit, Collection values, - boolean hasMore) { + boolean hasMore) throws Exception { return null; } - @Override public void deleteAll() { + @Override public void deleteAll() throws Exception { } } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedReadableDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedReadableDataSource.java index dec2eb21..375fb6e8 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedReadableDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedReadableDataSource.java @@ -29,5 +29,5 @@ public interface PaginatedReadableDataSource { * @param offset Index of the first item to be retrieved * @param limit Number of elements that will be retrieved */ - PaginatedCollection getPage(int offset, int limit); + PaginatedCollection getPage(int offset, int limit) throws Exception; } diff --git a/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedWriteableDataSource.java b/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedWriteableDataSource.java index 3f058cfa..20299617 100644 --- a/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedWriteableDataSource.java +++ b/rosie/src/main/java/com/karumi/rosie/repository/datasource/paginated/PaginatedWriteableDataSource.java @@ -36,10 +36,10 @@ public interface PaginatedWriteableDataSource> { * @param hasMore True whether the persisted page has more elements */ PaginatedCollection addOrUpdatePage(int offset, int limit, Collection values, - boolean hasMore); + boolean hasMore) throws Exception; /** * Deletes all the pages stored in this data source. */ - void deleteAll(); + void deleteAll() throws Exception; } diff --git a/rosie/src/test/java/com/karumi/rosie/repository/PaginatedRosieRepositoryTest.java b/rosie/src/test/java/com/karumi/rosie/repository/PaginatedRosieRepositoryTest.java index fcbc3328..001035d7 100644 --- a/rosie/src/test/java/com/karumi/rosie/repository/PaginatedRosieRepositoryTest.java +++ b/rosie/src/test/java/com/karumi/rosie/repository/PaginatedRosieRepositoryTest.java @@ -136,7 +136,7 @@ private PaginatedCollection givenCacheDataSourceReturnsNonVa } private PaginatedCollection givenCacheDataSourceReturnsValues(int offset, - int limit, boolean areValidValues) { + int limit, boolean areValidValues) throws Exception { PaginatedCollection values = getSomeValues(offset, limit); when(cacheDataSource.getPage(offset, limit)).thenReturn(values); when(cacheDataSource.isValid(any(AnyRepositoryValue.class))).thenReturn(areValidValues); @@ -144,7 +144,7 @@ private PaginatedCollection givenCacheDataSourceReturnsValue } private PaginatedCollection givenReadableDataSourceReturnsValues(int offset, - int limit) { + int limit) throws Exception { PaginatedCollection values = getSomeValues(offset, limit); when(readableDataSource.getPage(offset, limit)).thenReturn(values); return values; diff --git a/rosie/src/test/java/com/karumi/rosie/repository/RosieRepositoryTest.java b/rosie/src/test/java/com/karumi/rosie/repository/RosieRepositoryTest.java index f630fcdb..90990a36 100644 --- a/rosie/src/test/java/com/karumi/rosie/repository/RosieRepositoryTest.java +++ b/rosie/src/test/java/com/karumi/rosie/repository/RosieRepositoryTest.java @@ -344,7 +344,7 @@ private AnyRepositoryValue givenCacheDataSourceReturnsNonValidValueWithKey(AnyRe } @NonNull private AnyRepositoryValue givenCacheDataSourceReturnsValueWithKey(AnyRepositoryKey key, - boolean isValidValue) { + boolean isValidValue) throws Exception { AnyRepositoryValue value = new AnyRepositoryValue(key); when(cacheDataSource.getByKey(key)).thenReturn(value); when(cacheDataSource.isValid(value)).thenReturn(isValidValue); @@ -352,7 +352,8 @@ private AnyRepositoryValue givenCacheDataSourceReturnsNonValidValueWithKey(AnyRe } @NonNull - private AnyRepositoryValue givenReadableDataSourceReturnsValidValueWithKey(AnyRepositoryKey key) { + private AnyRepositoryValue givenReadableDataSourceReturnsValidValueWithKey(AnyRepositoryKey key) + throws Exception { AnyRepositoryValue value = new AnyRepositoryValue(key); when(readableDataSource.getByKey(key)).thenReturn(value); return value; @@ -367,7 +368,8 @@ private Collection givenCacheDataSourceReturnsNonValidValues return givenCacheDataSourceReturnsValues(false); } - private Collection givenCacheDataSourceReturnsValues(boolean areValidValues) { + private Collection givenCacheDataSourceReturnsValues(boolean areValidValues) + throws Exception { Collection values = getSomeValues(); when(cacheDataSource.getAll()).thenReturn(values); when(cacheDataSource.isValid(any(AnyRepositoryValue.class))).thenReturn(areValidValues); @@ -381,26 +383,29 @@ private Collection givenReadableDataSourceReturnsValidValues return values; } - private void givenReadableDataSourceThrowsException() { + private void givenReadableDataSourceThrowsException() throws Exception { when(readableDataSource.getAll()).thenThrow(new Exception()); } - private AnyRepositoryValue givenWriteableDataSourceWritesValue(AnyRepositoryValue value) { + private AnyRepositoryValue givenWriteableDataSourceWritesValue(AnyRepositoryValue value) + throws Exception { AnyRepositoryValue writeableValue = new AnyRepositoryValue(value.getKey()); when(writeableDataSource.addOrUpdate(value)).thenReturn(writeableValue); return writeableValue; } - private void givenWriteableDataSourceDoesNotWriteValue(AnyRepositoryValue value) { + private void givenWriteableDataSourceDoesNotWriteValue(AnyRepositoryValue value) + throws Exception { when(writeableDataSource.addOrUpdate(value)).thenReturn(null); } - private void givenWriteableDataSourceDoesNotWriteValues(Collection values) { + private void givenWriteableDataSourceDoesNotWriteValues(Collection values) + throws Exception { when(writeableDataSource.addOrUpdateAll(values)).thenReturn(null); } private Collection givenWriteableDataSourceWritesValues( - Collection values) { + Collection values) throws Exception { Collection updatedValues = new LinkedList<>(values); when(writeableDataSource.addOrUpdateAll(values)).thenReturn(values); return updatedValues; diff --git a/sample/build.gradle b/sample/build.gradle index ea86e470..f00f1305 100644 --- a/sample/build.gradle +++ b/sample/build.gradle @@ -16,6 +16,32 @@ apply plugin: 'com.android.application' +private Properties loadMarvelProperties() { + Properties props = new Properties() + props.load(new FileInputStream("./sample/marvel.properties")) + props +} + +private checkMarvelProperties() { + new File("./sample/marvel.properties").exists() +} + +def getPublicMarvelKey() { + if (checkMarvelProperties()) { + Properties props = loadMarvelProperties() + return props['MARVEL_PUBLIC_KEY'] + } + "null" +} + +def getPrivateMarvelKey() { + if (checkMarvelProperties()) { + Properties props = loadMarvelProperties() + return props['MARVEL_PRIVATE_KEY'] + } + "null" +} + android { compileSdkVersion 23 buildToolsVersion "23.0.1" @@ -26,9 +52,13 @@ android { targetSdkVersion 23 versionCode 1 versionName "1.0" + buildConfigField "String", "MARVEL_PUBLIC_KEY", getPublicMarvelKey() + buildConfigField "String", "MARVEL_PRIVATE_KEY", getPrivateMarvelKey() } } + + dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' @@ -38,6 +68,7 @@ dependencies { compile 'com.squareup.picasso:picasso:2.5.2' compile 'com.karumi:dividers:1.0.3' compile 'com.victor:lib:1.0.1' // spinner + compile 'com.karumi:MarvelApiClient:0.0.1' provided 'com.squareup.dagger:dagger-compiler:1.2.2' compile project(':rosie') } diff --git a/sample/src/main/java/com/karumi/rosie/sample/base/mapper/Mapper.java b/sample/src/main/java/com/karumi/rosie/sample/base/mapper/Mapper.java new file mode 100644 index 00000000..f40cf98d --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/base/mapper/Mapper.java @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.base.mapper; + +import java.util.ArrayList; +import java.util.Collection; + +public abstract class Mapper { + public abstract T2 map(T1 value); + public abstract T1 reverseMap(T2 value); + + public Collection map(Collection values) { + Collection returnValues = new ArrayList<>(); + for (T1 value : values) { + returnValues.add(map(value)); + } + return returnValues; + } + + public Collection reverseMap(Collection values) { + Collection returnValues = new ArrayList<>(); + for (T2 value : values) { + returnValues.add(reverseMap(value)); + } + return returnValues; + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/domain/usecase/GetCharacterDetails.java b/sample/src/main/java/com/karumi/rosie/sample/characters/domain/usecase/GetCharacterDetails.java index 838920dd..9c3a8d99 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/characters/domain/usecase/GetCharacterDetails.java +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/domain/usecase/GetCharacterDetails.java @@ -30,7 +30,7 @@ public class GetCharacterDetails extends RosieUseCase { this.charactersRepository = charactersRepository; } - @UseCase public void getCharacterDetails(String characterKey) { + @UseCase public void getCharacterDetails(String characterKey) throws Exception { Character character = charactersRepository.getByKey(characterKey); notifySuccess(character); } diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharacterDataSourceFactory.java b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharacterDataSourceFactory.java new file mode 100644 index 00000000..b0a96111 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharacterDataSourceFactory.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.characters.repository; + +import com.karumi.marvelapiclient.CharacterApiClient; +import com.karumi.marvelapiclient.MarvelApiConfig; +import com.karumi.rosie.sample.BuildConfig; +import com.karumi.rosie.sample.characters.repository.datasource.CharacterDataSource; +import com.karumi.rosie.sample.characters.repository.datasource.CharactersApiDataSource; +import com.karumi.rosie.sample.characters.repository.datasource.CharactersFakeDataSource; +import javax.inject.Inject; + +class CharacterDataSourceFactory { + + @Inject public CharacterDataSourceFactory() { + } + + CharacterDataSource createDataSource() { + if (hasKeys()) { + MarvelApiConfig marvelApiConfig = + MarvelApiConfig.with(BuildConfig.MARVEL_PUBLIC_KEY, BuildConfig.MARVEL_PRIVATE_KEY); + CharacterApiClient characterApiClient = new CharacterApiClient(marvelApiConfig); + return new CharactersApiDataSource(characterApiClient); + } else { + return new CharactersFakeDataSource(); + } + } + + private boolean hasKeys() { + return BuildConfig.MARVEL_PUBLIC_KEY != null && BuildConfig.MARVEL_PRIVATE_KEY != null; + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharactersRepository.java b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharactersRepository.java index 133d6012..00d790b0 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharactersRepository.java +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/CharactersRepository.java @@ -20,21 +20,23 @@ import com.karumi.rosie.repository.datasource.CacheDataSource; import com.karumi.rosie.repository.datasource.paginated.PaginatedCacheDataSource; import com.karumi.rosie.sample.characters.domain.model.Character; -import com.karumi.rosie.sample.characters.repository.datasource.CharactersApiDataSource; +import com.karumi.rosie.sample.characters.repository.datasource.CharacterDataSource; import com.karumi.rosie.sample.main.ApplicationModule; import javax.inject.Inject; import javax.inject.Named; public class CharactersRepository extends PaginatedRosieRepository { - @Inject public CharactersRepository(CharactersApiDataSource apiDataSource, + @Inject public CharactersRepository(CharacterDataSourceFactory characterDataSourceFactory, @Named(ApplicationModule.CHARACTERS_PAGE_IN_MEMORY_CACHE) PaginatedCacheDataSource inMemoryPaginatedCache, @Named(ApplicationModule.CHARACTERS_IN_MEMORY_CACHE) CacheDataSource inMemoryCache) { - addReadableDataSources(apiDataSource); addCacheDataSources(inMemoryCache); - addPaginatedReadableDataSources(apiDataSource); addPaginatedCacheDataSources(inMemoryPaginatedCache); + + CharacterDataSource characterDataSource = characterDataSourceFactory.createDataSource(); + addReadableDataSources(characterDataSource); + addPaginatedReadableDataSources(characterDataSource); } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharacterDataSource.java b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharacterDataSource.java new file mode 100644 index 00000000..0391381f --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharacterDataSource.java @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.characters.repository.datasource; + +import com.karumi.rosie.repository.datasource.EmptyReadableDataSource; +import com.karumi.rosie.repository.datasource.paginated.PaginatedReadableDataSource; +import com.karumi.rosie.sample.characters.domain.model.Character; + +public abstract class CharacterDataSource extends EmptyReadableDataSource +implements PaginatedReadableDataSource { +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersApiDataSource.java b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersApiDataSource.java index 13f334bd..3f4ab137 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersApiDataSource.java +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersApiDataSource.java @@ -16,18 +16,19 @@ package com.karumi.rosie.sample.characters.repository.datasource; -import android.support.annotation.NonNull; +import com.karumi.marvelapiclient.CharacterApiClient; +import com.karumi.marvelapiclient.MarvelApiException; +import com.karumi.marvelapiclient.model.CharacterDto; +import com.karumi.marvelapiclient.model.CharactersDto; +import com.karumi.marvelapiclient.model.MarvelResponse; import com.karumi.rosie.repository.PaginatedCollection; -import com.karumi.rosie.repository.datasource.EmptyReadableDataSource; -import com.karumi.rosie.repository.datasource.paginated.PaginatedReadableDataSource; import com.karumi.rosie.sample.characters.domain.model.Character; +import com.karumi.rosie.sample.characters.repository.datasource.mapper.MapperCharacterToCharacterDto; import java.util.Collection; -import java.util.LinkedList; import java.util.Random; import javax.inject.Inject; -public class CharactersApiDataSource extends EmptyReadableDataSource - implements PaginatedReadableDataSource { +public class CharactersApiDataSource extends CharacterDataSource { private static final int NUMBER_OF_CHARACTERS = 45; private static final long SLEEP_TIME_IN_MILLISECONDS = 1000; @@ -37,130 +38,32 @@ public class CharactersApiDataSource extends EmptyReadableDataSource characterResponse = characterApiClient.getCharacter(key); + CharacterDto characterDto = characterResponse.getResponse(); - fakeDelay(); - - switch (key) { - case SPIDERMAN_KEY: - character = getSpiderman(); - break; - case CAPTAIN_MARVEL_KEY: - character = getCaptainMarvel(); - break; - case HULK_KEY: - character = getHulk(); - break; - case THOR_KEY: - character = getThor(); - break; - case IRON_MAN_KEY: - default: - character = getIronMan(); - break; - } - - return character; + return mapper.reverseMap(characterDto); } - @Override public PaginatedCollection getPage(int offset, int limit) { - Collection characters = new LinkedList<>(); - - fakeDelay(); + @Override public PaginatedCollection getPage(int offset, int limit) + throws MarvelApiException { + MarvelResponse charactersApiResponse = characterApiClient.getAll(offset, limit); - for (int i = offset; i - offset < limit && i < NUMBER_OF_CHARACTERS; i++) { - characters.add(getCharacter(i)); - } + CharactersDto charactersDto = charactersApiResponse.getResponse(); + Collection characters = mapper.reverseMap(charactersDto.getCharacters()); PaginatedCollection charactersPage = new PaginatedCollection<>(characters); charactersPage.setOffset(offset); charactersPage.setLimit(limit); - charactersPage.setHasMore(offset + characters.size() < NUMBER_OF_CHARACTERS); + charactersPage.setHasMore( + charactersDto.getOffset() + charactersDto.getCount() < charactersDto.getTotal()); return charactersPage; } - - private Character getCharacter(int i) { - Character[] characters = - {getSpiderman(), getCaptainMarvel(), getHulk(), getThor(), getIronMan()}; - - Character character = characters[RANDOM.nextInt(characters.length)]; - character.setName(character.getName() + " " + i); - return character; - } - - @NonNull private Character getSpiderman() { - Character spiderman = new Character(); - spiderman.setKey(SPIDERMAN_KEY); - spiderman.setName("Spiderman"); - spiderman.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/6/60/538cd3628a05e.jpg"); - spiderman.setDescription( - "Bitten by a radioactive spider, high school student Peter Parker gained the speed, " - + "strength and powers of a spider. Adopting the name Spider-Man, Peter hoped to start" - + " a career using his new abilities. Taught that with great power comes great" - + " responsibility, Spidey has vowed to use his powers to help people."); - return spiderman; - } - - @NonNull private Character getCaptainMarvel() { - Character captainMarvel = new Character(); - captainMarvel.setKey(CAPTAIN_MARVEL_KEY); - captainMarvel.setName("Captain Marvel"); - captainMarvel.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/6/30/537ba61b764b4.jpg"); - captainMarvel.setDescription( - "Carol Danvers entered the Air Force upon graduating from high school to pursue her love" - + " of aircrafts and her dreams of flying."); - return captainMarvel; - } - - @NonNull private Character getHulk() { - Character hulk = new Character(); - hulk.setKey(HULK_KEY); - hulk.setName("Hulk"); - hulk.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/e/e0/537bafa34baa9.jpg"); - hulk.setDescription( - "Caught in a gamma bomb explosion while trying to save the life of a teenager, Dr. Bruce" - + " Banner was transformed into the incredibly powerful creature called the Hulk. An" - + " all too often misunderstood hero, the angrier the Hulk gets, the stronger the Hulk" - + " gets."); - return hulk; - } - - @NonNull private Character getThor() { - Character hulk = new Character(); - hulk.setKey(THOR_KEY); - hulk.setName("Thor"); - hulk.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/7/10/537bc71e9286f.jpg"); - hulk.setDescription( - "As the Norse God of thunder and lightning, Thor wields one of the greatest weapons ever" - + " made, the enchanted hammer Mjolnir. While others have described Thor as an" - + " over-muscled, oafish imbecile, he's quite smart and compassionate." - + " He's self-assured, and he would never, ever stop fighting for a worthwhile cause."); - return hulk; - } - - @NonNull private Character getIronMan() { - Character hulk = new Character(); - hulk.setKey(IRON_MAN_KEY); - hulk.setName("Iron Man"); - hulk.setThumbnailUrl("http://i.annihil.us/u/prod/marvel/i/mg/c/60/55b6a28ef24fa.jpg"); - hulk.setDescription( - "Wounded, captured and forced to build a weapon by his enemies, billionaire industrialist" - + " Tony Stark instead created an advanced suit of armor to save his life and escape" - + " captivity. Now with a new outlook on life, Tony uses his money and intelligence" - + " to make the world a safer, better place as Iron Man."); - return hulk; - } - - private void fakeDelay() { - try { - Thread.sleep(SLEEP_TIME_IN_MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersFakeDataSource.java b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersFakeDataSource.java new file mode 100644 index 00000000..84d0c7c3 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/CharactersFakeDataSource.java @@ -0,0 +1,163 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.characters.repository.datasource; + +import android.support.annotation.NonNull; +import com.karumi.marvelapiclient.MarvelApiException; +import com.karumi.rosie.repository.PaginatedCollection; +import com.karumi.rosie.sample.characters.domain.model.Character; +import java.util.Collection; +import java.util.LinkedList; +import java.util.Random; +import javax.inject.Inject; + +public class CharactersFakeDataSource extends CharacterDataSource { + + private static final int NUMBER_OF_CHARACTERS = 45; + private static final long SLEEP_TIME_IN_MILLISECONDS = 1000; + private static final Random RANDOM = new Random(System.nanoTime()); + private static final String SPIDERMAN_KEY = "54"; + private static final String CAPTAIN_MARVEL_KEY = "9"; + private static final String HULK_KEY = "25"; + private static final String THOR_KEY = "60"; + private static final String IRON_MAN_KEY = "29"; + + @Inject public CharactersFakeDataSource() { + } + + @Override public Character getByKey(String key) throws Exception { + Character character; + fakeDelay(); + + switch (key) { + case SPIDERMAN_KEY: + character = getSpiderman(); + break; + case CAPTAIN_MARVEL_KEY: + character = getCaptainMarvel(); + break; + case HULK_KEY: + character = getHulk(); + break; + case THOR_KEY: + character = getThor(); + break; + case IRON_MAN_KEY: + default: + character = getIronMan(); + break; + } + + return character; + } + + @Override public PaginatedCollection getPage(int offset, int limit) + throws MarvelApiException { + Collection characters = new LinkedList<>(); + fakeDelay(); + + for (int i = offset; i - offset < limit && i < NUMBER_OF_CHARACTERS; i++) { + characters.add(getCharacter(i)); + } + + PaginatedCollection charactersPage = new PaginatedCollection<>(characters); + charactersPage.setOffset(offset); + charactersPage.setLimit(limit); + charactersPage.setHasMore(offset + characters.size() < NUMBER_OF_CHARACTERS); + return charactersPage; + } + + private Character getCharacter(int i) { + Character[] characters = + {getSpiderman(), getCaptainMarvel(), getHulk(), getThor(), getIronMan()}; + + Character character = characters[RANDOM.nextInt(characters.length)]; + character.setName(character.getName() + " " + i); + return character; + } + + @NonNull private Character getSpiderman() { + Character spiderman = new Character(); + spiderman.setKey(SPIDERMAN_KEY); + spiderman.setName("Spiderman"); + spiderman.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/6/60/538cd3628a05e.jpg"); + spiderman.setDescription( + "Bitten by a radioactive spider, high school student Peter Parker gained the speed, " + + "strength and powers of a spider. Adopting the name Spider-Man, Peter hoped to start" + + " a career using his new abilities. Taught that with great power comes great" + + " responsibility, Spidey has vowed to use his powers to help people."); + return spiderman; + } + + @NonNull private Character getCaptainMarvel() { + Character captainMarvel = new Character(); + captainMarvel.setKey(CAPTAIN_MARVEL_KEY); + captainMarvel.setName("Captain Marvel"); + captainMarvel.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/6/30/537ba61b764b4.jpg"); + captainMarvel.setDescription( + "Carol Danvers entered the Air Force upon graduating from high school to pursue her love" + + " of aircrafts and her dreams of flying."); + return captainMarvel; + } + + @NonNull private Character getHulk() { + Character hulk = new Character(); + hulk.setKey(HULK_KEY); + hulk.setName("Hulk"); + hulk.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/e/e0/537bafa34baa9.jpg"); + hulk.setDescription( + "Caught in a gamma bomb explosion while trying to save the life of a teenager, Dr. Bruce" + + " Banner was transformed into the incredibly powerful creature called the Hulk. An" + + " all too often misunderstood hero, the angrier the Hulk gets, the stronger the Hulk" + + " gets."); + return hulk; + } + + @NonNull private Character getThor() { + Character hulk = new Character(); + hulk.setKey(THOR_KEY); + hulk.setName("Thor"); + hulk.setThumbnailUrl("http://x.annihil.us/u/prod/marvel/i/mg/7/10/537bc71e9286f.jpg"); + hulk.setDescription( + "As the Norse God of thunder and lightning, Thor wields one of the greatest weapons ever" + + " made, the enchanted hammer Mjolnir. While others have described Thor as an" + + " over-muscled, oafish imbecile, he's quite smart and compassionate." + + " He's self-assured, and he would never, ever stop fighting for a worthwhile cause."); + return hulk; + } + + @NonNull private Character getIronMan() { + Character hulk = new Character(); + hulk.setKey(IRON_MAN_KEY); + hulk.setName("Iron Man"); + hulk.setThumbnailUrl("http://i.annihil.us/u/prod/marvel/i/mg/c/60/55b6a28ef24fa.jpg"); + hulk.setDescription( + "Wounded, captured and forced to build a weapon by his enemies, billionaire industrialist" + + " Tony Stark instead created an advanced suit of armor to save his life and escape" + + " captivity. Now with a new outlook on life, Tony uses his money and intelligence" + + " to make the world a safer, better place as Iron Man."); + return hulk; + } + + private void fakeDelay() { + try { + Thread.sleep(SLEEP_TIME_IN_MILLISECONDS); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/mapper/MapperCharacterToCharacterDto.java b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/mapper/MapperCharacterToCharacterDto.java new file mode 100644 index 00000000..8d52cbc2 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/characters/repository/datasource/mapper/MapperCharacterToCharacterDto.java @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.characters.repository.datasource.mapper; + +import com.karumi.marvelapiclient.model.CharacterDto; +import com.karumi.marvelapiclient.model.MarvelImage; +import com.karumi.rosie.sample.base.mapper.Mapper; +import com.karumi.rosie.sample.characters.domain.model.Character; + +public class MapperCharacterToCharacterDto extends Mapper { + + @Override public CharacterDto map(Character value) { + throw new UnsupportedOperationException(); + } + + @Override public Character reverseMap(CharacterDto value) { + + Character character = new Character(); + character.setKey(value.getId()); + character.setName(value.getName()); + character.setDescription(value.getDescription()); + character.setThumbnailUrl(value.getThumbnail().getImageUrl(MarvelImage.Size.PORTRAIT_UNCANNY)); + return character; + } +} diff --git a/sample/src/main/java/com/karumi/rosie/sample/comics/domain/usecase/GetComicSeriesDetails.java b/sample/src/main/java/com/karumi/rosie/sample/comics/domain/usecase/GetComicSeriesDetails.java index 8864facc..c120cdcc 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/comics/domain/usecase/GetComicSeriesDetails.java +++ b/sample/src/main/java/com/karumi/rosie/sample/comics/domain/usecase/GetComicSeriesDetails.java @@ -30,7 +30,7 @@ public class GetComicSeriesDetails extends RosieUseCase { this.repository = repository; } - @UseCase public void getComicSeriesDetails(int comicSeriesKey) { + @UseCase public void getComicSeriesDetails(int comicSeriesKey) throws Exception { ComicSeries comicSeries = repository.getByKey(comicSeriesKey); notifySuccess(comicSeries); } diff --git a/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java b/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java index aab03f28..42e664c1 100644 --- a/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java +++ b/sample/src/main/java/com/karumi/rosie/sample/main/view/activity/MainActivity.java @@ -20,21 +20,29 @@ import android.os.Bundle; import android.support.design.widget.TabLayout; import android.support.v4.view.ViewPager; +import android.view.View; +import android.widget.TextView; import butterknife.Bind; import com.karumi.rosie.sample.R; import com.karumi.rosie.sample.characters.view.fragment.CharactersFragment; import com.karumi.rosie.sample.comics.view.fragment.ComicSeriesFragment; import com.karumi.rosie.sample.main.MainModule; import com.karumi.rosie.sample.main.view.adapter.FragmentAdapter; +import com.karumi.rosie.sample.main.view.presenter.FakeDataPresenter; +import com.karumi.rosie.view.Presenter; import com.karumi.rosie.view.RosieActivity; import java.util.Arrays; import java.util.List; +import javax.inject.Inject; -public class MainActivity extends RosieActivity { +public class MainActivity extends RosieActivity implements FakeDataPresenter.View { @Bind(R.id.vp_main) ViewPager viewPager; @Bind(R.id.tab_page_indicator) TabLayout pagerTabView; + @Bind(R.id.tv_disclaimer) TextView disclaimerView; + private FragmentAdapter adapter; + @Inject @Presenter FakeDataPresenter fakeDataPresenter; @Override protected int getLayoutId() { return R.layout.activity_main; @@ -61,4 +69,18 @@ private void initializeViewPager() { pagerTabView.setupWithViewPager(viewPager); } + + @Override public void showFakeDisclaimer() { + disclaimerView.setVisibility(View.VISIBLE); + } + + @Override public void hideFakeDisclaymer() { + disclaimerView.setVisibility(View.GONE); + } + + @Override public void hideLoading() { + } + + @Override public void showLoading() { + } } diff --git a/sample/src/main/java/com/karumi/rosie/sample/main/view/presenter/FakeDataPresenter.java b/sample/src/main/java/com/karumi/rosie/sample/main/view/presenter/FakeDataPresenter.java new file mode 100644 index 00000000..47d2ad57 --- /dev/null +++ b/sample/src/main/java/com/karumi/rosie/sample/main/view/presenter/FakeDataPresenter.java @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 Karumi. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.karumi.rosie.sample.main.view.presenter; + +import com.karumi.rosie.domain.usecase.UseCaseHandler; +import com.karumi.rosie.sample.BuildConfig; +import com.karumi.rosie.view.RosiePresenter; +import com.karumi.rosie.view.loading.RosiePresenterWithLoading; +import javax.inject.Inject; + +public class FakeDataPresenter extends RosiePresenter { + @Inject public FakeDataPresenter(UseCaseHandler useCaseHandler) { + super(useCaseHandler); + } + + @Override protected void initialize() { + super.initialize(); + if (BuildConfig.MARVEL_PUBLIC_KEY == null || BuildConfig.MARVEL_PRIVATE_KEY == null) { + getView().showFakeDisclaimer(); + } else { + getView().hideFakeDisclaymer(); + } + } + + public interface View extends RosiePresenterWithLoading.View { + void showFakeDisclaimer(); + + void hideFakeDisclaymer(); + } +} diff --git a/sample/src/main/res/layout/activity_main.xml b/sample/src/main/res/layout/activity_main.xml index c9602c78..f03d2a11 100644 --- a/sample/src/main/res/layout/activity_main.xml +++ b/sample/src/main/res/layout/activity_main.xml @@ -23,6 +23,13 @@ android:background="@color/main_background" > + Comic thumbnail See character details Character thumbnail + Mavel keys doesn\'t exist, you need it to access to real data. + This is the DEMO mode with fake information. + diff --git a/sample/src/main/res/values/styles.xml b/sample/src/main/res/values/styles.xml index 63882d25..29638a09 100644 --- a/sample/src/main/res/values/styles.xml +++ b/sample/src/main/res/values/styles.xml @@ -39,6 +39,13 @@ true + +