Allow reading downloaded chapters

This commit is contained in:
inorichi 2015-11-03 21:27:56 +01:00
parent 62ae572c72
commit 11638ae917
20 changed files with 93 additions and 19 deletions

View File

@ -48,10 +48,9 @@ public class DownloadManager {
.subscribe(); .subscribe();
} }
private Observable<Page> downloadChapter(Manga manga, Chapter chapter) { public Observable<Page> downloadChapter(Manga manga, Chapter chapter) {
final Source source = sourceManager.get(manga.source); final Source source = sourceManager.get(manga.source);
final File chapterDirectory = new File( final File chapterDirectory = getAbsoluteChapterDirectory(source, manga, chapter);
preferences.getDownloadsDirectory(), getChapterDirectory(source, manga, chapter));
return source return source
.pullPageListFromNetwork(chapter.url) .pullPageListFromNetwork(chapter.url)
@ -65,7 +64,12 @@ public class DownloadManager {
.flatMap(page -> getDownloadedImage(page, source, chapterDirectory)); .flatMap(page -> getDownloadedImage(page, source, chapterDirectory));
} }
private String getChapterDirectory(Source source, Manga manga, Chapter chapter) { public File getAbsoluteChapterDirectory(Source source, Manga manga, Chapter chapter) {
return new File(preferences.getDownloadsDirectory(),
getChapterDirectory(source, manga, chapter));
}
public String getChapterDirectory(Source source, Manga manga, Chapter chapter) {
return source.getName() + return source.getName() +
File.separator + File.separator +
manga.title.replaceAll("[^a-zA-Z0-9.-]", "_") + manga.title.replaceAll("[^a-zA-Z0-9.-]", "_") +

View File

@ -32,6 +32,12 @@ public class Chapter {
@StorIOSQLiteColumn(name = ChaptersTable.COLUMN_DATE_UPLOAD) @StorIOSQLiteColumn(name = ChaptersTable.COLUMN_DATE_UPLOAD)
public long 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() {} public Chapter() {}

View File

@ -1,15 +1,18 @@
package eu.kanade.mangafeed.events; package eu.kanade.mangafeed.events;
import eu.kanade.mangafeed.data.models.Chapter; import eu.kanade.mangafeed.data.models.Chapter;
import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.sources.base.Source; import eu.kanade.mangafeed.sources.base.Source;
public class SourceChapterEvent { public class SourceMangaChapterEvent {
private Source source; private Source source;
private Manga manga;
private Chapter chapter; private Chapter chapter;
public SourceChapterEvent(Source source, Chapter chapter) { public SourceMangaChapterEvent(Source source, Manga manga, Chapter chapter) {
this.source = source; this.source = source;
this.manga = manga;
this.chapter = chapter; this.chapter = chapter;
} }
@ -17,6 +20,10 @@ public class SourceChapterEvent {
return source; return source;
} }
public Manga getManga() {
return manga;
}
public Chapter getChapter() { public Chapter getChapter() {
return chapter; return chapter;
} }

View File

@ -2,17 +2,20 @@ package eu.kanade.mangafeed.presenter;
import android.os.Bundle; import android.os.Bundle;
import java.io.File;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import eu.kanade.mangafeed.data.helpers.DatabaseHelper; 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.helpers.SourceManager;
import eu.kanade.mangafeed.data.models.Chapter; import eu.kanade.mangafeed.data.models.Chapter;
import eu.kanade.mangafeed.data.models.Manga; import eu.kanade.mangafeed.data.models.Manga;
import eu.kanade.mangafeed.events.ChapterCountEvent; 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.sources.base.Source;
import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment; import eu.kanade.mangafeed.ui.fragment.MangaChaptersFragment;
import eu.kanade.mangafeed.util.EventBusHook; import eu.kanade.mangafeed.util.EventBusHook;
@ -26,6 +29,8 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
@Inject DatabaseHelper db; @Inject DatabaseHelper db;
@Inject SourceManager sourceManager; @Inject SourceManager sourceManager;
@Inject PreferencesHelper preferences;
@Inject DownloadManager downloadManager;
private Manga manga; private Manga manga;
private Source source; private Source source;
@ -111,7 +116,7 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
} }
public void onChapterClicked(Chapter chapter) { public void onChapterClicked(Chapter chapter) {
EventBus.getDefault().postSticky(new SourceChapterEvent(source, chapter)); EventBus.getDefault().postSticky(new SourceMangaChapterEvent(source, manga, chapter));
} }
public void markChaptersRead(Observable<Chapter> selectedChapters, boolean read) { public void markChaptersRead(Observable<Chapter> selectedChapters, boolean read) {
@ -131,4 +136,14 @@ public class MangaChaptersPresenter extends BasePresenter<MangaChaptersFragment>
})); }));
} }
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;
}
}
} }

View File

@ -2,16 +2,19 @@ package eu.kanade.mangafeed.presenter;
import android.os.Bundle; import android.os.Bundle;
import java.io.File;
import java.util.List; import java.util.List;
import javax.inject.Inject; import javax.inject.Inject;
import de.greenrobot.event.EventBus; import de.greenrobot.event.EventBus;
import eu.kanade.mangafeed.data.helpers.DatabaseHelper; 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.PreferencesHelper;
import eu.kanade.mangafeed.data.models.Chapter; 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.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.sources.base.Source;
import eu.kanade.mangafeed.ui.activity.ReaderActivity; import eu.kanade.mangafeed.ui.activity.ReaderActivity;
import eu.kanade.mangafeed.util.EventBusHook; import eu.kanade.mangafeed.util.EventBusHook;
@ -25,14 +28,17 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
@Inject PreferencesHelper prefs; @Inject PreferencesHelper prefs;
@Inject DatabaseHelper db; @Inject DatabaseHelper db;
@Inject DownloadManager downloadManager;
private Source source; private Source source;
private Manga manga;
private Chapter chapter; private Chapter chapter;
private List<Page> pageList; private List<Page> pageList;
@State int currentPage; @State int currentPage;
private static final int GET_PAGE_LIST = 1; private static final int GET_PAGE_LIST = 1;
private static final int GET_PAGE_IMAGES = 2; private static final int GET_PAGE_IMAGES = 2;
private static final int GET_LOCAL_IMAGES = 3;
@Override @Override
protected void onCreate(Bundle savedState) { protected void onCreate(Bundle savedState) {
@ -41,7 +47,7 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
restartableLatestCache(GET_PAGE_LIST, restartableLatestCache(GET_PAGE_LIST,
() -> getPageListObservable() () -> getPageListObservable()
.doOnNext(pages -> pageList = pages) .doOnNext(pages -> pageList = pages)
.doOnCompleted(() -> start(GET_PAGE_IMAGES)), .doOnCompleted(this::prepareChapter),
(view, pages) -> { (view, pages) -> {
view.onPageListReady(pages); view.onPageListReady(pages);
if (currentPage != 0) if (currentPage != 0)
@ -55,6 +61,10 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
(view, page) -> { (view, page) -> {
}, },
(view, error) -> Timber.e("An error occurred while downloading an image")); (view, error) -> Timber.e("An error occurred while downloading an image"));
restartableReplay(GET_LOCAL_IMAGES,
this::getLocalImagesObservable,
(view, page) -> {});
} }
@Override @Override
@ -77,14 +87,16 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
} }
@EventBusHook @EventBusHook
public void onEventMainThread(SourceChapterEvent event) { public void onEventMainThread(SourceMangaChapterEvent event) {
source = event.getSource(); source = event.getSource();
manga = event.getManga();
chapter = event.getChapter(); chapter = event.getChapter();
if (chapter.last_page_read != 0 && !chapter.read) if (chapter.last_page_read != 0 && !chapter.read)
currentPage = chapter.last_page_read; currentPage = chapter.last_page_read;
start(1); start(GET_PAGE_LIST);
EventBus.getDefault().removeStickyEvent(SourceChapterEvent.class);
EventBus.getDefault().removeStickyEvent(SourceMangaChapterEvent.class);
} }
private Observable<List<Page>> getPageListObservable() { private Observable<List<Page>> getPageListObservable() {
@ -103,10 +115,26 @@ public class ReaderPresenter extends BasePresenter<ReaderActivity> {
.observeOn(AndroidSchedulers.mainThread()); .observeOn(AndroidSchedulers.mainThread());
} }
private Observable<Page> 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) { public void setCurrentPage(int currentPage) {
this.currentPage = currentPage; this.currentPage = currentPage;
} }
private void prepareChapter() {
if (chapter.downloaded != Chapter.DOWNLOADED)
start(GET_PAGE_IMAGES);
else
start(GET_LOCAL_IMAGES);
}
private void saveChapter() { private void saveChapter() {
chapter.last_page_read = currentPage; chapter.last_page_read = currentPage;
if (currentPage == pageList.size() - 1) { if (currentPage == pageList.size() - 1) {

View File

@ -1,6 +1,5 @@
package eu.kanade.mangafeed.ui.adapter; package eu.kanade.mangafeed.ui.adapter;
import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -11,16 +10,17 @@ import java.util.List;
import eu.davidea.flexibleadapter.FlexibleAdapter; import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.models.Chapter; 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.fragment.base.BaseFragment;
import eu.kanade.mangafeed.ui.holder.ChaptersHolder; import eu.kanade.mangafeed.ui.holder.ChaptersHolder;
public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> { public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
private Context context; private BaseFragment fragment;
public OnItemClickListener clickListener; public OnItemClickListener clickListener;
public ChaptersAdapter(BaseFragment fragment) { public ChaptersAdapter(BaseFragment fragment) {
this.context = fragment.getActivity(); this.fragment = fragment;
mItems = new ArrayList<>(); mItems = new ArrayList<>();
clickListener = (OnItemClickListener) fragment; clickListener = (OnItemClickListener) fragment;
} }
@ -30,14 +30,14 @@ public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
@Override @Override
public ChaptersHolder onCreateViewHolder(ViewGroup parent, int viewType) { 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); return new ChaptersHolder(v, this);
} }
@Override @Override
public void onBindViewHolder(ChaptersHolder holder, int position) { public void onBindViewHolder(ChaptersHolder holder, int position) {
final Chapter chapter = getItem(position); final Chapter chapter = getItem(position);
holder.onSetValues(context, chapter); holder.onSetValues(fragment.getActivity(), chapter);
} }
public void setItems(List<Chapter> chapters) { public void setItems(List<Chapter> chapters) {
@ -49,4 +49,8 @@ public class ChaptersAdapter extends FlexibleAdapter<ChaptersHolder, Chapter> {
boolean onListItemClick(int position); boolean onListItemClick(int position);
void onListItemLongClick(int position); void onListItemLongClick(int position);
} }
public MangaChaptersFragment getMangaChaptersFragment() {
return (MangaChaptersFragment) fragment;
}
} }

View File

@ -37,6 +37,8 @@ public class CatalogueHolder extends ItemViewHolder<Manga> {
.diskCacheStrategy(DiskCacheStrategy.RESULT) .diskCacheStrategy(DiskCacheStrategy.RESULT)
.centerCrop() .centerCrop()
.into(image); .into(image);
} else {
image.setImageResource(android.R.color.transparent);
} }
} }
} }

View File

@ -38,7 +38,7 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements
public void onSetValues(Context context, Chapter chapter) { public void onSetValues(Context context, Chapter chapter) {
title.setText(chapter.name); title.setText(chapter.name);
download_icon.setImageResource(R.drawable.ic_file_download_black_48dp);
if (chapter.read) { if (chapter.read) {
title.setTextColor(ContextCompat.getColor(context, R.color.chapter_read_text)); title.setTextColor(ContextCompat.getColor(context, R.color.chapter_read_text));
@ -52,6 +52,14 @@ public class ChaptersHolder extends RecyclerView.ViewHolder implements
pages.setText(""); 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(); toggleActivation();
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 265 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 295 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 365 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 B