Эх сурвалжийг харах

Add catalogue detail page. Add simple tests for sources

inorichi 9 жил өмнө
parent
commit
8da5c83cb3

+ 2 - 0
app/src/main/AndroidManifest.xml

@@ -15,6 +15,7 @@
         <activity
             android:name=".ui.activity.MainActivity"
             android:label="@string/label_main"
+            android:launchMode="singleTop"
             android:theme="@style/AppTheme.NoActionBar" >
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
@@ -34,6 +35,7 @@
             android:name=".ui.activity.CatalogueActivity"
             android:label="@string/title_activity_catalogue_list"
             android:parentActivityName=".ui.activity.MainActivity"
+            android:launchMode="singleTop"
             android:theme="@style/AppTheme" >
             <meta-data
                 android:name="android.support.PARENT_ACTIVITY"

+ 18 - 3
app/src/main/java/eu/kanade/mangafeed/presenter/CataloguePresenter.java

@@ -24,6 +24,7 @@ import nucleus.presenter.RxPresenter;
 import rx.Observable;
 import rx.Subscription;
 import rx.android.schedulers.AndroidSchedulers;
+import rx.internal.util.SubscriptionList;
 import rx.schedulers.Schedulers;
 import rx.subjects.PublishSubject;
 import timber.log.Timber;
@@ -46,6 +47,7 @@ public class CataloguePresenter extends RxPresenter<CatalogueActivity> {
     private Subscription mMangaDetailFetchSubscription;
     private PublishSubject<Observable<String>> mSearchViewPublishSubject;
     private PublishSubject<Observable<List<Manga>>> mMangaDetailPublishSubject;
+    private SubscriptionList mResultSubscriptions = new SubscriptionList();
 
     private final String CURRENT_PAGE = "CATALOGUE_CURRENT_PAGE";
 
@@ -81,6 +83,12 @@ public class CataloguePresenter extends RxPresenter<CatalogueActivity> {
         state.putInt(CURRENT_PAGE, mCurrentPage);
     }
 
+    @Override
+    protected void onDestroy() {
+        super.onDestroy();
+        mResultSubscriptions.unsubscribe();
+    }
+
     private void initializeSearch() {
         remove(mSearchViewSubscription);
 
@@ -126,16 +134,17 @@ public class CataloguePresenter extends RxPresenter<CatalogueActivity> {
                 .filter(manga -> manga.initialized)
                 .onBackpressureBuffer()
                 .observeOn(AndroidSchedulers.mainThread())
-                .subscribe(manga -> {
+                .compose(deliverReplay())
+                .subscribe(this.split((view, manga) -> {
                     // Get manga index in the adapter
                     int index = getMangaIndex(manga);
                     // Get the image view associated with the manga.
                     // If it's null (not visible in the screen) there's no need to update the image.
-                    ImageView imageView = getView().getImageView(index);
+                    ImageView imageView = view.getImageView(index);
                     if (imageView != null) {
                         updateImage(imageView, manga.thumbnail_url);
                     }
-                });
+                }));
 
         add(mMangaDetailFetchSubscription);
     }
@@ -143,11 +152,15 @@ public class CataloguePresenter extends RxPresenter<CatalogueActivity> {
     public void getMangasFromSource(int page) {
         mMangaFetchSubscription = getMangasSubscriber(
                 selectedSource.pullPopularMangasFromNetwork(page));
+
+        mResultSubscriptions.add(mMangaFetchSubscription);
     }
 
     public void getMangasFromSearch(int page) {
         mMangaSearchSubscription = getMangasSubscriber(
                 selectedSource.searchMangasFromNetwork(mSearchName, page));
+
+        mResultSubscriptions.add(mMangaSearchSubscription);
     }
 
     private Subscription getMangasSubscriber(Observable<List<Manga>> mangas) {
@@ -195,10 +208,12 @@ public class CataloguePresenter extends RxPresenter<CatalogueActivity> {
         // If going to search mode
         else if (mSearchName.equals("") && !query.equals("")) {
             mSearchMode = true;
+            mResultSubscriptions.clear();
         }
         // If going to normal mode
         else if (!mSearchName.equals("") && query.equals("")) {
             mSearchMode = false;
+            mResultSubscriptions.clear();
         }
 
         mSearchName = query;

+ 0 - 8
app/src/main/java/eu/kanade/mangafeed/presenter/LibraryPresenter.java

@@ -33,14 +33,6 @@ public class LibraryPresenter extends BasePresenter {
     public LibraryPresenter(LibraryView view) {
         this.view = view;
         App.getComponent(view.getActivity()).inject(this);
-
-        //TODO remove, only for testing
-        if (prefs.isFirstRun()) {
-            db.insertMangas(DummyDataUtil.createDummyManga()).toBlocking().single();
-            db.insertChapters(DummyDataUtil.createDummyChapters()).subscribe();
-            prefs.setNotFirstRun();
-        }
-
     }
 
     public void onMangaClick(int position) {

+ 1 - 0
app/src/main/java/eu/kanade/mangafeed/presenter/MangaCataloguePresenter.java

@@ -25,5 +25,6 @@ public class MangaCataloguePresenter extends BasePresenter {
 
     private void initializeManga() {
         view.setTitle(manga.title);
+        view.setMangaInformation(manga);
     }
 }

+ 35 - 2
app/src/main/java/eu/kanade/mangafeed/ui/activity/MangaCatalogueActivity.java

@@ -2,17 +2,30 @@ package eu.kanade.mangafeed.ui.activity;
 
 import android.os.Bundle;
 import android.support.v7.widget.Toolbar;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.bumptech.glide.Glide;
+import com.bumptech.glide.load.engine.DiskCacheStrategy;
 
 import butterknife.Bind;
 import butterknife.ButterKnife;
 import eu.kanade.mangafeed.R;
+import eu.kanade.mangafeed.data.models.Manga;
 import eu.kanade.mangafeed.presenter.MangaCataloguePresenter;
 import eu.kanade.mangafeed.view.MangaCatalogueView;
 
 public class MangaCatalogueActivity extends BaseActivity implements MangaCatalogueView {
 
-    @Bind(R.id.toolbar)
-    Toolbar toolbar;
+    @Bind(R.id.toolbar) Toolbar toolbar;
+
+    @Bind(R.id.manga_artist) TextView mArtist;
+    @Bind(R.id.manga_author) TextView mAuthor;
+    @Bind(R.id.manga_chapters) TextView mChapters;
+    @Bind(R.id.manga_genres) TextView mGenres;
+    @Bind(R.id.manga_status) TextView mStatus;
+    @Bind(R.id.manga_summary) TextView mDescription;
+    @Bind(R.id.manga_cover) ImageView mCover;
 
     private MangaCataloguePresenter presenter;
 
@@ -40,8 +53,28 @@ public class MangaCatalogueActivity extends BaseActivity implements MangaCatalog
         super.onStop();
     }
 
+    // MangaCatalogueView
+
     @Override
     public void setTitle(String title) {
         setToolbarTitle(title);
     }
+
+    @Override
+    public void setMangaInformation(Manga manga) {
+        mArtist.setText(manga.artist);
+        mAuthor.setText(manga.author);
+        mChapters.setText("0"); // TODO
+        mGenres.setText(manga.genre);
+        mStatus.setText("Ongoing"); //TODO
+        mDescription.setText(manga.description);
+
+        Glide.with(getActivity())
+                .load(manga.thumbnail_url)
+                .diskCacheStrategy(DiskCacheStrategy.RESULT)
+                .centerCrop()
+                .into(mCover);
+    }
+
+
 }

+ 3 - 0
app/src/main/java/eu/kanade/mangafeed/view/MangaCatalogueView.java

@@ -1,5 +1,8 @@
 package eu.kanade.mangafeed.view;
 
+import eu.kanade.mangafeed.data.models.Manga;
+
 public interface MangaCatalogueView extends BaseView {
     void setTitle(String title);
+    void setMangaInformation(Manga manga);
 }

BIN
app/src/main/res/drawable-xhdpi/bkg_shadow_img.9.png


+ 185 - 0
app/src/main/res/layout/activity_manga_catalogue.xml

@@ -11,6 +11,191 @@
         android:id="@+id/toolbar"
         layout="@layout/toolbar"/>
 
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:padding="10dp">
 
+        <RelativeLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@drawable/bkg_shadow_img"
+            android:focusable="false"
+            android:focusableInTouchMode="false"
+            android:gravity="center"
+            android:padding="4dp">
+
+            <ImageView
+                android:id="@+id/manga_cover"
+                android:layout_width="138dp"
+                android:layout_height="190dp"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:scaleType="fitXY"
+                android:visibility="visible" />
+
+        </RelativeLayout>
+
+        <RelativeLayout
+            android:id="@+id/grid_item_description"
+            android:layout_width="fill_parent"
+            android:layout_height="wrap_content"
+            android:focusable="false"
+            android:focusableInTouchMode="false"
+            android:paddingLeft="15.0dip">
+
+            <TextView
+                android:id="@+id/manga_author_label"
+                style="@style/manga_detail_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentLeft="true"
+                android:layout_alignRight="@+id/manga_genres_label"
+                android:layout_marginTop="5dp"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:text="@string/author" />
+
+            <TextView
+                android:id="@+id/manga_author"
+                style="@style/manga_detail_text"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_alignBaseline="@id/manga_author_label"
+                android:layout_toRightOf="@id/manga_author_label"
+                android:ellipsize="end"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:maxLines="1"
+                android:singleLine="true" />
+
+            <TextView
+                android:id="@+id/manga_artist_label"
+                style="@style/manga_detail_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentLeft="true"
+                android:layout_alignRight="@id/manga_genres_label"
+                android:layout_below="@id/manga_author_label"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:text="@string/artist" />
+
+            <TextView
+                android:id="@+id/manga_artist"
+                style="@style/manga_detail_text"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_alignBaseline="@id/manga_artist_label"
+                android:layout_toRightOf="@id/manga_artist_label"
+                android:ellipsize="end"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:maxLines="1"
+                android:singleLine="true" />
+
+            <TextView
+                android:id="@+id/manga_chapters_label"
+                style="@style/manga_detail_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentLeft="true"
+                android:layout_alignRight="@id/manga_genres_label"
+                android:layout_below="@id/manga_artist_label"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:text="@string/chapters" />
+
+            <TextView
+                android:id="@+id/manga_chapters"
+                style="@style/manga_detail_text"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_alignBaseline="@id/manga_chapters_label"
+                android:layout_toRightOf="@id/manga_chapters_label"
+                android:ellipsize="end"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:maxLines="1"
+                android:singleLine="true" />
+
+            <TextView
+                android:id="@+id/manga_status_label"
+                style="@style/manga_detail_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentLeft="true"
+                android:layout_alignRight="@id/manga_genres_label"
+                android:layout_below="@id/manga_chapters_label"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:text="@string/status" />
+
+            <TextView
+                android:id="@+id/manga_status"
+                style="@style/manga_detail_text"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_alignBaseline="@id/manga_status_label"
+                android:layout_toRightOf="@id/manga_chapters_label"
+                android:ellipsize="end"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:maxLines="1"
+                android:singleLine="true" />
+
+            <TextView
+                android:id="@+id/manga_genres_label"
+                style="@style/manga_detail_label"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_alignParentLeft="true"
+                android:layout_below="@id/manga_status_label"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                android:text="@string/genres" />
+
+            <TextView
+                android:id="@+id/manga_genres"
+                style="@style/manga_detail_text"
+                android:layout_width="fill_parent"
+                android:layout_height="wrap_content"
+                android:layout_below="@id/manga_genres_label"
+                android:singleLine="false"
+                android:focusable="false"
+                android:focusableInTouchMode="false"
+                 />
+
+
+        </RelativeLayout>
+
+    </LinearLayout>
+
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:padding="10dp"
+        android:orientation="vertical">
+
+        <TextView
+            android:id="@+id/manga_summary_label"
+            style="@style/manga_detail_label"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:focusable="false"
+            android:focusableInTouchMode="false"
+            android:singleLine="false"
+            android:text="@string/description" />
+
+        <TextView
+            android:id="@+id/manga_summary"
+            style="@style/manga_detail_text"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:focusable="false"
+            android:focusableInTouchMode="false"
+            android:singleLine="false" />
+
+    </LinearLayout>
 
 </LinearLayout>

+ 7 - 0
app/src/main/res/values/strings.xml

@@ -36,5 +36,12 @@
     <string name="action_delete">Delete</string>
     <string name="library_selection_title">Selected</string>
     <string name="title_activity_catalogue_list">CatalogueList</string>
+    <string name="title_activity_manga_catalogue">MangaCatalogue</string>
+    <string name="author">Author</string>
+    <string name="chapters">Chapters</string>
+    <string name="genres">Genres</string>
+    <string name="artist">Artist</string>
+    <string name="status">Status</string>
+    <string name="description">Description</string>
 
 </resources>

+ 17 - 0
app/src/main/res/values/styles.xml

@@ -81,4 +81,21 @@
         <item name="android:visibility">gone</item>
     </style>
 
+    <style name="manga_detail_label">
+        <item name="android:textSize">15sp</item>
+        <item name="android:textStyle">bold</item>
+        <item name="android:textColor">#ff58595b</item>
+        <item name="android:ellipsize">end</item>
+        <item name="android:paddingRight">10dp</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:textIsSelectable">false</item>
+    </style>
+    <style name="manga_detail_text">
+        <item name="android:textSize">15sp</item>
+        <item name="android:textStyle">normal</item>
+        <item name="android:textColor">#ff808285</item>
+        <item name="android:ellipsize">end</item>
+        <item name="android:singleLine">true</item>
+        <item name="android:textIsSelectable">false</item>
+    </style>
 </resources>

+ 34 - 1
app/src/test/java/eu/kanade/mangafeed/BatotoTest.java

@@ -15,8 +15,10 @@ import java.util.List;
 
 import eu.kanade.mangafeed.data.caches.CacheManager;
 import eu.kanade.mangafeed.data.helpers.NetworkHelper;
+import eu.kanade.mangafeed.data.models.Chapter;
 import eu.kanade.mangafeed.data.models.Manga;
 import eu.kanade.mangafeed.sources.Batoto;
+import eu.kanade.mangafeed.sources.Source;
 import rx.android.schedulers.AndroidSchedulers;
 import rx.observers.TestSubscriber;
 import rx.schedulers.Schedulers;
@@ -27,8 +29,11 @@ public class BatotoTest {
 
     NetworkHelper net;
     CacheManager cache;
-    Batoto b;
+    Source b;
     final String chapterUrl ="http://bato.to/read/_/345144/minamoto-kun-monogatari_ch178_by_vortex-scans";
+    final String mangaUrl = "http://bato.to/comic/_/comics/natsuzora-and-run-r9597";
+    final String mangaUrl2 = "http://bato.to/comic/_/comics/bungaku-shoujo-to-shinitagari-no-pierrot-r534";
+    final String nisekoiUrl = "http://bato.to/comic/_/comics/nisekoi-r951";
 
     @Before
     public void setUp() {
@@ -50,6 +55,34 @@ public class BatotoTest {
         List<Manga> mangaList = b.pullPopularMangasFromNetwork(1)
                 .toBlocking().first();
 
+        Manga m = mangaList.get(0);
+        Assert.assertNotNull(m.title);
+        Assert.assertNotNull(m.artist);
+        Assert.assertNotNull(m.author);
+        Assert.assertNotNull(m.url);
+
         Assert.assertTrue(mangaList.size() > 25);
     }
+
+    @Test
+    public void testChapterList() {
+        List<Chapter> mangaList = b.pullChaptersFromNetwork(mangaUrl)
+                .toBlocking().first();
+
+        Assert.assertTrue(mangaList.size() > 5);
+    }
+
+    @Test
+    public void testMangaDetails() {
+        Manga nisekoi = b.pullMangaFromNetwork(nisekoiUrl)
+                .toBlocking().single();
+
+        Assert.assertEquals("Nisekoi", nisekoi.title);
+        Assert.assertEquals("Komi Naoshi", nisekoi.author);
+        Assert.assertEquals("Komi Naoshi", nisekoi.artist);
+        Assert.assertEquals("http://bato.to/comic/_/nisekoi-r951", nisekoi.url);
+        Assert.assertEquals("http://img.bato.to/forums/uploads/a2a850c644a50bccc462f36922c1cbf2.jpg", nisekoi.thumbnail_url);
+        Assert.assertTrue(nisekoi.description.length() > 20);
+        Assert.assertTrue(nisekoi.genre.length() > 20);
+    }
 }

+ 80 - 0
app/src/test/java/eu/kanade/mangafeed/MangahereTest.java

@@ -0,0 +1,80 @@
+package eu.kanade.mangafeed;
+
+import android.os.Build;
+
+import junit.framework.Assert;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricGradleTestRunner;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+
+import java.util.List;
+
+import eu.kanade.mangafeed.data.caches.CacheManager;
+import eu.kanade.mangafeed.data.helpers.NetworkHelper;
+import eu.kanade.mangafeed.data.models.Chapter;
+import eu.kanade.mangafeed.data.models.Manga;
+import eu.kanade.mangafeed.sources.MangaHere;
+import eu.kanade.mangafeed.sources.Source;
+
+@Config(constants = BuildConfig.class, sdk = Build.VERSION_CODES.LOLLIPOP)
+@RunWith(RobolectricGradleTestRunner.class)
+public class MangahereTest {
+
+    NetworkHelper net;
+    CacheManager cache;
+    Source b;
+    final String chapterUrl ="http://www.mangahere.co/manga/kimi_ni_todoke/v15/c099/";
+    final String mangaUrl = "http://www.mangahere.co/manga/kimi_ni_todoke/";
+
+    @Before
+    public void setUp() {
+        net = new NetworkHelper();
+        cache = new CacheManager(RuntimeEnvironment.application.getApplicationContext());
+        b = new MangaHere(net, cache);
+    }
+
+    @Test
+    public void testImageList() {
+        List<String> imageUrls = b.getImageUrlsFromNetwork(chapterUrl)
+                .toList().toBlocking().single();
+
+        Assert.assertTrue(imageUrls.size() > 5);
+    }
+
+    @Test
+    public void testMangaList() {
+        List<Manga> mangaList = b.pullPopularMangasFromNetwork(1)
+                .toBlocking().first();
+
+        Manga m = mangaList.get(0);
+        Assert.assertNotNull(m.title);
+        Assert.assertNotNull(m.url);
+
+        Assert.assertTrue(mangaList.size() > 25);
+    }
+
+    @Test
+    public void testChapterList() {
+        List<Chapter> mangaList = b.pullChaptersFromNetwork(mangaUrl)
+                .toBlocking().first();
+
+        Assert.assertTrue(mangaList.size() > 5);
+    }
+
+    @Test
+    public void testMangaDetails() {
+        Manga manga = b.pullMangaFromNetwork(mangaUrl)
+                .toBlocking().single();
+
+        Assert.assertEquals("Shiina Karuho", manga.author);
+        Assert.assertEquals("Shiina Karuho", manga.artist);
+        Assert.assertEquals("http://www.mangahere.co/manga/kimi_ni_todoke/", manga.url);
+        Assert.assertEquals("http://a.mhcdn.net/store/manga/4999/cover.jpg?v=1433950383", manga.thumbnail_url);
+        Assert.assertTrue(manga.description.length() > 20);
+        Assert.assertTrue(manga.genre.length() > 20);
+    }
+}