From 11638ae917834ca36f1a122761b8ad9a9ce828f5 Mon Sep 17 00:00:00 2001 From: inorichi Date: Tue, 3 Nov 2015 21:27:56 +0100 Subject: [PATCH] Allow reading downloaded chapters --- .../data/helpers/DownloadManager.java | 12 ++++-- .../kanade/mangafeed/data/models/Chapter.java | 6 +++ ...vent.java => SourceMangaChapterEvent.java} | 11 ++++- .../presenter/MangaChaptersPresenter.java | 19 ++++++++- .../mangafeed/presenter/ReaderPresenter.java | 38 +++++++++++++++--- .../mangafeed/ui/adapter/ChaptersAdapter.java | 14 ++++--- .../mangafeed/ui/holder/CatalogueHolder.java | 2 + .../mangafeed/ui/holder/ChaptersHolder.java | 10 ++++- .../drawable-hdpi/ic_action_delete_36dp.png | Bin 0 -> 213 bytes .../ic_file_download_black_36dp.png | Bin 0 -> 204 bytes .../drawable-ldpi/ic_action_delete_36dp.png | Bin 0 -> 252 bytes .../ic_file_download_black_36dp.png | Bin 0 -> 265 bytes .../drawable-mdpi/ic_action_delete_36dp.png | Bin 0 -> 160 bytes .../ic_file_download_black_36dp.png | Bin 0 -> 161 bytes .../drawable-xhdpi/ic_action_delete_36dp.png | Bin 0 -> 201 bytes .../ic_file_download_black_36dp.png | Bin 0 -> 200 bytes .../drawable-xxhdpi/ic_action_delete_36dp.png | Bin 0 -> 298 bytes .../ic_file_download_black_36dp.png | Bin 0 -> 295 bytes .../ic_action_delete_36dp.png | Bin 0 -> 365 bytes .../ic_file_download_black_36dp.png | Bin 0 -> 348 bytes 20 files changed, 93 insertions(+), 19 deletions(-) rename app/src/main/java/eu/kanade/mangafeed/events/{SourceChapterEvent.java => SourceMangaChapterEvent.java} (58%) create mode 100644 app/src/main/res/drawable-hdpi/ic_action_delete_36dp.png create mode 100644 app/src/main/res/drawable-hdpi/ic_file_download_black_36dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_action_delete_36dp.png create mode 100644 app/src/main/res/drawable-ldpi/ic_file_download_black_36dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_delete_36dp.png create mode 100644 app/src/main/res/drawable-mdpi/ic_file_download_black_36dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_delete_36dp.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_file_download_black_36dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_delete_36dp.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_file_download_black_36dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_delete_36dp.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_file_download_black_36dp.png diff --git a/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java b/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java index f7a38b786d..3aa2ee4f58 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/helpers/DownloadManager.java @@ -48,10 +48,9 @@ public class DownloadManager { .subscribe(); } - private Observable downloadChapter(Manga manga, Chapter chapter) { + public Observable downloadChapter(Manga manga, Chapter chapter) { final Source source = sourceManager.get(manga.source); - final File chapterDirectory = new File( - preferences.getDownloadsDirectory(), getChapterDirectory(source, manga, chapter)); + final File chapterDirectory = getAbsoluteChapterDirectory(source, manga, chapter); return source .pullPageListFromNetwork(chapter.url) @@ -64,8 +63,13 @@ public class DownloadManager { // Start downloading images .flatMap(page -> getDownloadedImage(page, source, chapterDirectory)); } + + public File getAbsoluteChapterDirectory(Source source, Manga manga, Chapter chapter) { + return new File(preferences.getDownloadsDirectory(), + getChapterDirectory(source, manga, chapter)); + } - private String getChapterDirectory(Source source, Manga manga, Chapter chapter) { + public String getChapterDirectory(Source source, Manga manga, Chapter chapter) { return source.getName() + File.separator + manga.title.replaceAll("[^a-zA-Z0-9.-]", "_") + diff --git a/app/src/main/java/eu/kanade/mangafeed/data/models/Chapter.java b/app/src/main/java/eu/kanade/mangafeed/data/models/Chapter.java index 86dd0d101c..034990c3ad 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/models/Chapter.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/models/Chapter.java @@ -32,6 +32,12 @@ public class Chapter { @StorIOSQLiteColumn(name = ChaptersTable.COLUMN_DATE_UPLOAD) public long date_upload; + public int downloaded; + + public static final int UNKNOWN = 0; + public static final int NOT_DOWNLOADED = 1; + public static final int DOWNLOADED = 2; + public Chapter() {} diff --git a/app/src/main/java/eu/kanade/mangafeed/events/SourceChapterEvent.java b/app/src/main/java/eu/kanade/mangafeed/events/SourceMangaChapterEvent.java similarity index 58% rename from app/src/main/java/eu/kanade/mangafeed/events/SourceChapterEvent.java rename to app/src/main/java/eu/kanade/mangafeed/events/SourceMangaChapterEvent.java index c9fcf1c6f5..c26b8e920a 100644 --- a/app/src/main/java/eu/kanade/mangafeed/events/SourceChapterEvent.java +++ b/app/src/main/java/eu/kanade/mangafeed/events/SourceMangaChapterEvent.java @@ -1,15 +1,18 @@ package eu.kanade.mangafeed.events; import eu.kanade.mangafeed.data.models.Chapter; +import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.sources.base.Source; -public class SourceChapterEvent { +public class SourceMangaChapterEvent { private Source source; + private Manga manga; private Chapter chapter; - public SourceChapterEvent(Source source, Chapter chapter) { + public SourceMangaChapterEvent(Source source, Manga manga, Chapter chapter) { this.source = source; + this.manga = manga; this.chapter = chapter; } @@ -17,6 +20,10 @@ public class SourceChapterEvent { return source; } + public Manga getManga() { + return manga; + } + public Chapter getChapter() { return chapter; } diff --git a/app/src/main/java/eu/kanade/mangafeed/presenter/MangaChaptersPresenter.java b/app/src/main/java/eu/kanade/mangafeed/presenter/MangaChaptersPresenter.java index 6b85278553..fa41f545fe 100644 --- a/app/src/main/java/eu/kanade/mangafeed/presenter/MangaChaptersPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/presenter/MangaChaptersPresenter.java @@ -2,17 +2,20 @@ package eu.kanade.mangafeed.presenter; import android.os.Bundle; +import java.io.File; import java.util.List; import javax.inject.Inject; import de.greenrobot.event.EventBus; import eu.kanade.mangafeed.data.helpers.DatabaseHelper; +import eu.kanade.mangafeed.data.helpers.DownloadManager; +import eu.kanade.mangafeed.data.helpers.PreferencesHelper; import eu.kanade.mangafeed.data.helpers.SourceManager; import eu.kanade.mangafeed.data.models.Chapter; import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.events.ChapterCountEvent; -import eu.kanade.mangafeed.events.SourceChapterEvent; +import eu.kanade.mangafeed.events.SourceMangaChapterEvent; import eu.kanade.mangafeed.sources.base.Source; import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment; import eu.kanade.mangafeed.util.EventBusHook; @@ -26,6 +29,8 @@ public class MangaChaptersPresenter extends BasePresenter @Inject DatabaseHelper db; @Inject SourceManager sourceManager; + @Inject PreferencesHelper preferences; + @Inject DownloadManager downloadManager; private Manga manga; private Source source; @@ -111,7 +116,7 @@ public class MangaChaptersPresenter extends BasePresenter } public void onChapterClicked(Chapter chapter) { - EventBus.getDefault().postSticky(new SourceChapterEvent(source, chapter)); + EventBus.getDefault().postSticky(new SourceMangaChapterEvent(source, manga, chapter)); } public void markChaptersRead(Observable selectedChapters, boolean read) { @@ -131,4 +136,14 @@ public class MangaChaptersPresenter extends BasePresenter })); } + + public void checkIsChapterDownloaded(Chapter chapter) { + File dir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter); + + if (dir.exists() && dir.listFiles().length > 0) { + chapter.downloaded = Chapter.DOWNLOADED; + } else { + chapter.downloaded = Chapter.NOT_DOWNLOADED; + } + } } diff --git a/app/src/main/java/eu/kanade/mangafeed/presenter/ReaderPresenter.java b/app/src/main/java/eu/kanade/mangafeed/presenter/ReaderPresenter.java index e711f377ab..53921a45a7 100644 --- a/app/src/main/java/eu/kanade/mangafeed/presenter/ReaderPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/presenter/ReaderPresenter.java @@ -2,16 +2,19 @@ package eu.kanade.mangafeed.presenter; import android.os.Bundle; +import java.io.File; import java.util.List; import javax.inject.Inject; import de.greenrobot.event.EventBus; import eu.kanade.mangafeed.data.helpers.DatabaseHelper; +import eu.kanade.mangafeed.data.helpers.DownloadManager; import eu.kanade.mangafeed.data.helpers.PreferencesHelper; import eu.kanade.mangafeed.data.models.Chapter; +import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.data.models.Page; -import eu.kanade.mangafeed.events.SourceChapterEvent; +import eu.kanade.mangafeed.events.SourceMangaChapterEvent; import eu.kanade.mangafeed.sources.base.Source; import eu.kanade.mangafeed.ui.activity.ReaderActivity; import eu.kanade.mangafeed.util.EventBusHook; @@ -25,14 +28,17 @@ public class ReaderPresenter extends BasePresenter { @Inject PreferencesHelper prefs; @Inject DatabaseHelper db; + @Inject DownloadManager downloadManager; private Source source; + private Manga manga; private Chapter chapter; private List pageList; @State int currentPage; private static final int GET_PAGE_LIST = 1; private static final int GET_PAGE_IMAGES = 2; + private static final int GET_LOCAL_IMAGES = 3; @Override protected void onCreate(Bundle savedState) { @@ -41,7 +47,7 @@ public class ReaderPresenter extends BasePresenter { restartableLatestCache(GET_PAGE_LIST, () -> getPageListObservable() .doOnNext(pages -> pageList = pages) - .doOnCompleted(() -> start(GET_PAGE_IMAGES)), + .doOnCompleted(this::prepareChapter), (view, pages) -> { view.onPageListReady(pages); if (currentPage != 0) @@ -55,6 +61,10 @@ public class ReaderPresenter extends BasePresenter { (view, page) -> { }, (view, error) -> Timber.e("An error occurred while downloading an image")); + + restartableReplay(GET_LOCAL_IMAGES, + this::getLocalImagesObservable, + (view, page) -> {}); } @Override @@ -77,14 +87,16 @@ public class ReaderPresenter extends BasePresenter { } @EventBusHook - public void onEventMainThread(SourceChapterEvent event) { + public void onEventMainThread(SourceMangaChapterEvent event) { source = event.getSource(); + manga = event.getManga(); chapter = event.getChapter(); if (chapter.last_page_read != 0 && !chapter.read) currentPage = chapter.last_page_read; - start(1); - EventBus.getDefault().removeStickyEvent(SourceChapterEvent.class); + start(GET_PAGE_LIST); + + EventBus.getDefault().removeStickyEvent(SourceMangaChapterEvent.class); } private Observable> getPageListObservable() { @@ -103,10 +115,26 @@ public class ReaderPresenter extends BasePresenter { .observeOn(AndroidSchedulers.mainThread()); } + private Observable getLocalImagesObservable() { + File chapterDir = downloadManager.getAbsoluteChapterDirectory(source, manga, chapter); + + return Observable.from(pageList) + .flatMap(page -> downloadManager.getDownloadedImage(page, source, chapterDir)) + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()); + } + public void setCurrentPage(int currentPage) { this.currentPage = currentPage; } + private void prepareChapter() { + if (chapter.downloaded != Chapter.DOWNLOADED) + start(GET_PAGE_IMAGES); + else + start(GET_LOCAL_IMAGES); + } + private void saveChapter() { chapter.last_page_read = currentPage; if (currentPage == pageList.size() - 1) { diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/adapter/ChaptersAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/adapter/ChaptersAdapter.java index d98e1b86a2..4cb0383cd1 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/adapter/ChaptersAdapter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/adapter/ChaptersAdapter.java @@ -1,6 +1,5 @@ package eu.kanade.mangafeed.ui.adapter; -import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -11,16 +10,17 @@ import java.util.List; import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.models.Chapter; +import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment; import eu.kanade.mangafeed.ui.fragment.base.BaseFragment; import eu.kanade.mangafeed.ui.holder.ChaptersHolder; public class ChaptersAdapter extends FlexibleAdapter { - private Context context; + private BaseFragment fragment; public OnItemClickListener clickListener; public ChaptersAdapter(BaseFragment fragment) { - this.context = fragment.getActivity(); + this.fragment = fragment; mItems = new ArrayList<>(); clickListener = (OnItemClickListener) fragment; } @@ -30,14 +30,14 @@ public class ChaptersAdapter extends FlexibleAdapter { @Override public ChaptersHolder onCreateViewHolder(ViewGroup parent, int viewType) { - View v = LayoutInflater.from(context).inflate(R.layout.item_chapter, parent, false); + View v = LayoutInflater.from(fragment.getActivity()).inflate(R.layout.item_chapter, parent, false); return new ChaptersHolder(v, this); } @Override public void onBindViewHolder(ChaptersHolder holder, int position) { final Chapter chapter = getItem(position); - holder.onSetValues(context, chapter); + holder.onSetValues(fragment.getActivity(), chapter); } public void setItems(List chapters) { @@ -49,4 +49,8 @@ public class ChaptersAdapter extends FlexibleAdapter { boolean onListItemClick(int position); void onListItemLongClick(int position); } + + public MangaChaptersFragment getMangaChaptersFragment() { + return (MangaChaptersFragment) fragment; + } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/holder/CatalogueHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/holder/CatalogueHolder.java index c1850a4912..2e316420d7 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/holder/CatalogueHolder.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/holder/CatalogueHolder.java @@ -37,6 +37,8 @@ public class CatalogueHolder extends ItemViewHolder { .diskCacheStrategy(DiskCacheStrategy.RESULT) .centerCrop() .into(image); + } else { + image.setImageResource(android.R.color.transparent); } } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/holder/ChaptersHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/holder/ChaptersHolder.java index a904e74e78..7e3c214fcc 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/holder/ChaptersHolder.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/holder/ChaptersHolder.java @@ -38,7 +38,7 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements public void onSetValues(Context context, Chapter chapter) { title.setText(chapter.name); - download_icon.setImageResource(R.drawable.ic_file_download_black_48dp); + if (chapter.read) { title.setTextColor(ContextCompat.getColor(context, R.color.chapter_read_text)); @@ -52,6 +52,14 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements pages.setText(""); } + if (chapter.downloaded == Chapter.UNKNOWN) { + adapter.getMangaChaptersFragment().getPresenter().checkIsChapterDownloaded(chapter); + } + if (chapter.downloaded == Chapter.DOWNLOADED) + download_icon.setImageResource(R.drawable.ic_action_delete_36dp); + else if (chapter.downloaded == Chapter.NOT_DOWNLOADED) + download_icon.setImageResource(R.drawable.ic_file_download_black_36dp); + toggleActivation(); } diff --git a/app/src/main/res/drawable-hdpi/ic_action_delete_36dp.png b/app/src/main/res/drawable-hdpi/ic_action_delete_36dp.png new file mode 100644 index 0000000000000000000000000000000000000000..8377c1da7f8a820163f250d0a77fe8a5bab6c536 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL0wmRZ7KH(+Ii4<#Ar-gY-q_38U?9TsVDlwI z7nuWx7-d{_Sfe)@FMSZyw`A{rW|yAx^*eVPsl*Eg?P1{ge3Yfbgm>Knp`IBgveT!| zUJ<+_?Q6zlvmD)X?D?P}btR>><|_r0+YVPAMLM(ohD{UV>|o?(#v6dW%i_#5a> N22WQ%mvv4FO#pt%Q;q-t literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_file_download_black_36dp.png b/app/src/main/res/drawable-hdpi/ic_file_download_black_36dp.png new file mode 100644 index 0000000000000000000000000000000000000000..e8d3ec48724ca6b1c75b4d702df68a238459abf9 GIT binary patch literal 204 zcmeAS@N?(olHy`uVBq!ia0vp^W+2SL0wmRZ7KH(+$(}BbAr-gYUUTGgFc4^cXgNta z!m4fYp2c51_A(xFTGF;{S@V;>`P%zBygCfN?YDY4we(xW1kXqXw;l<@q;EGi+h8$K5-IKmsWNs`qZM*I402`ujeez3|BFWbritcA zYQCdH8N2Dn9btn5P8CIMjp3)O#CusERbHDr%z6SMq;DmjG&FSp0000fV9hxwh9#7mpptj7OGwTK zXBefRk+qUN#;^pA&?+HvSj(QoHkE)Y^qQcacf$3brpAjB*0UyjcS)YidlFsPiG=S) zXRwk8l53f1!>5ZaRB*GX*c;C6Pyr8U;5nmVPhr}n6gG}h+dnNF{pNfC{o_AdWFEmD P00000NkvXXu0mjfbJ1~8 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_delete_36dp.png b/app/src/main/res/drawable-mdpi/ic_action_delete_36dp.png new file mode 100644 index 0000000000000000000000000000000000000000..eec14f009a0cff5693eac90425c72e361118508a GIT binary patch literal 160 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8x~Gd{NX4z>1PRtD418@|ZEPwL zj3SDsXUOvWzxaUfQE%3P3q9OsJf_VnxTHE7To{vV%(5=5a9qsRD`m2T=a>718T*e& zmh>%fOz$v0(e{u#F4@j7LNNNzX@e(^b-sO;T;d*W{DhG~R^h;>n2Zy_Kr0zMUHx3v IIVCg!000Ix9smFU literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_file_download_black_36dp.png b/app/src/main/res/drawable-mdpi/ic_file_download_black_36dp.png new file mode 100644 index 0000000000000000000000000000000000000000..bdf434535370a07a0aff9c473f48eda4b65d68af GIT binary patch literal 161 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8hNp{TNX4zUQ!erzP~c#dJQ^tT z)~$H+x6N&4ysUPs9^PAi(v?L}Q>nyp>2H@43!OT>QWp6>HqTpRICtCo?-gA8Cf!k; zw74={@cqnchD*;pR(I%_7nw}&>Y3`@mnNMPf9=Dc|H7i$1x()Zf0NBNm*)cQWbkzL Kb6Mw<&;$Tv8aspl literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_delete_36dp.png b/app/src/main/res/drawable-xhdpi/ic_action_delete_36dp.png new file mode 100644 index 0000000000000000000000000000000000000000..3a25d9b62232d819e51323a7d0c2c53148cc77ac GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawCV09yhE&{od*dvxgM*0c!`+M6 z&7?$LxhRD!;Myo1-1uWBi{J~4QQ+xaHjvJRbkAg$P z3--Nv)eMYGEF1zr9x~&L=7pq(XY2yf8BOg1av7)E1+4mLv^@OLo{;BKdPPRxKiY&Y nHPd_cF*NT{x~h`WqT;m@bD0n9fAzEs=r#sVS3j3^P6~)y?&av!GMS5;*@=J z4>vM9{mF58Pr>mdKI;Vst0QufZ?f?J) literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_delete_36dp.png b/app/src/main/res/drawable-xxhdpi/ic_action_delete_36dp.png new file mode 100644 index 0000000000000000000000000000000000000000..51f5e8bcb7990f666564ff21095edfbe3898a4b4 GIT binary patch literal 298 zcmeAS@N?(olHy`uVBq!ia0vp^IUvlz0wh)Q=eq%^kDe}$Ar-gY-rnfT>?qK7QJzIL z;z-FOmWOf+c$j9txaF{j)rHq1A|!dD!jlsPss+n;N6J>+KeGGQbf0aVDxQ;;a7Hbc zHh8^sgPG;C^aC=#h5t|3DsW5U8dFAc~QH(4g)M;gUE)$V~Jn4 zaG9Om@oC2Ux;KVO&lgXdSIVbbv|r)U=6~MZQtQ78U3U1ABI|EmdZ};Tn#UQM*ZM9_ z-fFLV)yuwW)3?P-?@V{~zg8CYDz@ZH%2vD25zg8Nqx`fFN4aSqo#n56e3rZR$zQ(O zr+@irpZ(>deZI;+`(V}5t%`m+0$lUW(K*}NBKw^h&!Q;Q>miJ2vCf&Wcc9M!G2rap@t#oJNwu*PN zUX;yS*Lm#W%V`-l^Yl88J%^;k2qCx}RTx>U zFU-51Phl_VV7m33vDTIG?Wcyg#SLba4*g%n4;QbiWc?<{{3UFn?kn}C=MkH^azz=p zta)&4@@Jdy3jeRR41+tgbox9(Yc)-u<o>_u6{1-oD!M#aiwaKC>{%C gg7_Ll7JXsfcj&6d6+WRDV5l*8y85}Sb4q9e04Pp~*8l(j literal 0 HcmV?d00001