diff --git a/app/src/main/java/eu/kanade/mangafeed/data/cache/CoverCache.java b/app/src/main/java/eu/kanade/mangafeed/data/cache/CoverCache.java index 4248204457..dfaf2a10d6 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/cache/CoverCache.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/cache/CoverCache.java @@ -36,16 +36,24 @@ public class CoverCache { return !cacheDir.exists() && cacheDir.mkdirs(); } + public void save(String thumbnailUrl, LazyHeaders headers) { + save(thumbnailUrl, headers, null); + } + // Download the cover with Glide (it can avoid repeating requests) and save the file on this cache - public void save(String cover, LazyHeaders headers) { - GlideUrl url = new GlideUrl(cover, headers); + // Optionally, load the image in the given image view when the resource is ready, if not null + public void save(String thumbnailUrl, LazyHeaders headers, ImageView imageView) { + GlideUrl url = new GlideUrl(thumbnailUrl, headers); Glide.with(context) .load(url) .downloadOnly(new SimpleTarget() { @Override public void onResourceReady(File resource, GlideAnimation anim) { try { - add(cover, resource); + add(thumbnailUrl, resource); + if (imageView != null) { + loadFromCache(imageView, resource); + } } catch (IOException e) { e.printStackTrace(); } @@ -54,8 +62,9 @@ public class CoverCache { } // Copy the cover from Glide's cache to this cache - public void add(String key, File source) throws IOException { - File dest = new File(cacheDir, DiskUtils.hashKeyForDisk(key)); + public void add(String thumbnailUrl, File source) throws IOException { + createCacheDir(); + File dest = new File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)); if (dest.exists()) dest.delete(); @@ -78,37 +87,29 @@ public class CoverCache { } // Get the cover from cache - public File get(String key) { - return new File(cacheDir, DiskUtils.hashKeyForDisk(key)); + public File get(String thumbnailUrl) { + return new File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)); } // Delete the cover from cache - public boolean delete(String key) { - File file = new File(cacheDir, DiskUtils.hashKeyForDisk(key)); + public boolean delete(String thumbnailUrl) { + File file = new File(cacheDir, DiskUtils.hashKeyForDisk(thumbnailUrl)); return file.exists() && file.delete(); } - // Load the cover from cache or network if it doesn't exist - public void loadOrFetchInto(ImageView imageView, String cover, LazyHeaders headers) { - File localCover = get(cover); + // Save and load the image from cache + public void saveAndLoadFromCache(ImageView imageView, String thumbnailUrl, LazyHeaders headers) { + File localCover = get(thumbnailUrl); if (localCover.exists()) { - loadLocalInto(context, imageView, localCover); + loadFromCache(imageView, localCover); } else { - loadRemoteInto(context, imageView, cover, headers); + save(thumbnailUrl, headers, imageView); } } - // Load the cover from cache - public static void loadLocalInto(Context context, ImageView imageView, String cover) { - File cacheDir = new File(context.getCacheDir(), PARAMETER_CACHE_DIRECTORY); - File localCover = new File(cacheDir, DiskUtils.hashKeyForDisk(cover)); - if (localCover.exists()) { - loadLocalInto(context, imageView, localCover); - } - } - - // Load the cover from the cache directory into the specified image view - private static void loadLocalInto(Context context, ImageView imageView, File file) { + // Helper method to load the cover from the cache directory into the specified image view + // The file must exist + private void loadFromCache(ImageView imageView, File file) { Glide.with(context) .load(file) .diskCacheStrategy(DiskCacheStrategy.NONE) @@ -116,9 +117,10 @@ public class CoverCache { .into(imageView); } - // Load the cover from network into the specified image view. It does NOT save the image in cache - private static void loadRemoteInto(Context context, ImageView imageView, String cover, LazyHeaders headers) { - GlideUrl url = new GlideUrl(cover, headers); + // Helper method to load the cover from network into the specified image view. + // It does NOT save the image in cache + public void loadFromNetwork(ImageView imageView, String thumbnailUrl, LazyHeaders headers) { + GlideUrl url = new GlideUrl(thumbnailUrl, headers); Glide.with(context) .load(url) .diskCacheStrategy(DiskCacheStrategy.SOURCE) diff --git a/app/src/main/java/eu/kanade/mangafeed/data/download/model/DownloadQueue.java b/app/src/main/java/eu/kanade/mangafeed/data/download/model/DownloadQueue.java index 31ffcfdeed..02a5754ba7 100644 --- a/app/src/main/java/eu/kanade/mangafeed/data/download/model/DownloadQueue.java +++ b/app/src/main/java/eu/kanade/mangafeed/data/download/model/DownloadQueue.java @@ -25,7 +25,6 @@ public class DownloadQueue { public void remove(Download download) { queue.remove(download); - download.setStatus(Download.NOT_DOWNLOADED); download.setStatusSubject(null); } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryAdapter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryAdapter.java index a8eaa9907d..75ff027a27 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryAdapter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryAdapter.java @@ -1,6 +1,7 @@ package eu.kanade.mangafeed.ui.library; -import android.content.Context; +import android.view.View; +import android.view.ViewGroup; import android.widget.Filter; import android.widget.Filterable; @@ -14,10 +15,12 @@ public class LibraryAdapter extends EasyAdapter implements Filterable { List mangas; Filter filter; + private LibraryPresenter presenter; - public LibraryAdapter(Context context) { - super(context, LibraryHolder.class); + public LibraryAdapter(LibraryFragment fragment) { + super(fragment.getActivity(), LibraryHolder.class); filter = new LibraryFilter(); + presenter = fragment.getPresenter(); } public void setNewItems(List list) { @@ -57,9 +60,16 @@ public class LibraryAdapter extends EasyAdapter implements Filterable { @Override public void publishResults(CharSequence constraint, FilterResults results) { - setItems((List) results.values); + setItems((List) results.values); } } - + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = super.getView(position, convertView, parent); + LibraryHolder holder = (LibraryHolder) view.getTag(); + Manga manga = getItem(position); + holder.loadCover(manga, presenter.sourceManager.get(manga.source), presenter.coverCache); + return view; + } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java index 15f22a5dfd..57757a2938 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryFragment.java @@ -3,6 +3,7 @@ package eu.kanade.mangafeed.ui.library; import android.content.Intent; import android.os.Bundle; import android.support.v7.widget.SearchView; +import android.util.SparseBooleanArray; import android.view.ActionMode; import android.view.LayoutInflater; import android.view.Menu; @@ -20,9 +21,10 @@ import butterknife.OnItemClick; import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.sync.LibraryUpdateService; -import eu.kanade.mangafeed.ui.manga.MangaActivity; import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment; +import eu.kanade.mangafeed.ui.manga.MangaActivity; import nucleus.factory.RequiresPresenter; +import rx.Observable; @RequiresPresenter(LibraryPresenter.class) public class LibraryFragment extends BaseRxFragment { @@ -31,10 +33,7 @@ public class LibraryFragment extends BaseRxFragment { private LibraryAdapter adapter; public static LibraryFragment newInstance() { - LibraryFragment fragment = new LibraryFragment(); - Bundle args = new Bundle(); - fragment.setArguments(args); - return fragment; + return new LibraryFragment(); } @Override @@ -95,7 +94,7 @@ public class LibraryFragment extends BaseRxFragment { } private void createAdapter() { - adapter = new LibraryAdapter(getActivity()); + adapter = new LibraryAdapter(this); grid.setAdapter(adapter); } @@ -136,7 +135,7 @@ public class LibraryFragment extends BaseRxFragment { public boolean onActionItemClicked(ActionMode mode, MenuItem item) { switch (item.getItemId()) { case R.id.action_delete: - getPresenter().onDelete(grid.getCheckedItemPositions(), adapter); + getPresenter().deleteMangas(getSelectedMangas()); mode.finish(); return true; } @@ -150,4 +149,11 @@ public class LibraryFragment extends BaseRxFragment { }); } + private Observable getSelectedMangas() { + SparseBooleanArray checkedItems = grid.getCheckedItemPositions(); + return Observable.range(0, checkedItems.size()) + .map(checkedItems::keyAt) + .map(adapter::getItem); + } + } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java index ec81c0f5a7..6ff27628f8 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryHolder.java @@ -7,6 +7,7 @@ import android.widget.TextView; import eu.kanade.mangafeed.R; import eu.kanade.mangafeed.data.cache.CoverCache; import eu.kanade.mangafeed.data.database.models.Manga; +import eu.kanade.mangafeed.data.source.base.Source; import uk.co.ribot.easyadapter.ItemViewHolder; import uk.co.ribot.easyadapter.PositionInfo; import uk.co.ribot.easyadapter.annotations.LayoutId; @@ -17,11 +18,8 @@ import uk.co.ribot.easyadapter.annotations.ViewId; public class LibraryHolder extends ItemViewHolder { @ViewId(R.id.thumbnail) ImageView thumbnail; - @ViewId(R.id.title) TextView title; - @ViewId(R.id.author) TextView author; - @ViewId(R.id.unreadText) TextView unreadText; public LibraryHolder(View view) { @@ -38,12 +36,11 @@ public class LibraryHolder extends ItemViewHolder { } else { unreadText.setVisibility(View.GONE); } + } - if (manga.thumbnail_url != null) { - CoverCache.loadLocalInto(getContext(), thumbnail, manga.thumbnail_url); - } else { - thumbnail.setImageResource(android.R.color.transparent); - } + public void loadCover(Manga manga, Source source, CoverCache coverCache) { + if (manga.thumbnail_url != null) + coverCache.saveAndLoadFromCache(thumbnail, manga.thumbnail_url, source.getGlideHeaders()); } } diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java index 2cdac77e41..a6212eb49a 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/library/LibraryPresenter.java @@ -1,15 +1,16 @@ package eu.kanade.mangafeed.ui.library; import android.os.Bundle; -import android.util.SparseBooleanArray; import javax.inject.Inject; +import eu.kanade.mangafeed.data.cache.CoverCache; import eu.kanade.mangafeed.data.database.DatabaseHelper; +import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.data.preference.PreferencesHelper; +import eu.kanade.mangafeed.data.source.SourceManager; import eu.kanade.mangafeed.ui.base.presenter.BasePresenter; import rx.Observable; -import rx.Subscription; import rx.android.schedulers.AndroidSchedulers; import rx.schedulers.Schedulers; @@ -17,44 +18,28 @@ public class LibraryPresenter extends BasePresenter { @Inject DatabaseHelper db; @Inject PreferencesHelper prefs; + @Inject CoverCache coverCache; + @Inject SourceManager sourceManager; - private Subscription mFavoriteMangasSubscription; - private Subscription mDeleteMangaSubscription; + private static final int GET_MANGAS = 1; @Override protected void onCreate(Bundle savedState) { super.onCreate(savedState); + + restartableLatestCache(GET_MANGAS, + () -> db.getMangasWithUnread().createObservable() + .subscribeOn(Schedulers.io()) + .observeOn(AndroidSchedulers.mainThread()), + LibraryFragment::onNextMangas); + + start(GET_MANGAS); } - @Override - protected void onTakeView(LibraryFragment view) { - super.onTakeView(view); - getFavoriteMangas(); - } - - public void getFavoriteMangas() { - if (mFavoriteMangasSubscription != null) - return; - - add(mFavoriteMangasSubscription = db.getMangasWithUnread().createObservable() + public void deleteMangas(Observable selectedMangas) { + add(selectedMangas .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .compose(deliverLatestCache()) - .subscribe(this.split(LibraryFragment::onNextMangas))); - } - - public void onDelete(SparseBooleanArray checkedItems, LibraryAdapter adapter) { - if (mDeleteMangaSubscription != null) - remove(mDeleteMangaSubscription); - - add(mDeleteMangaSubscription = Observable.range(0, checkedItems.size()) - .observeOn(Schedulers.io()) - .map(checkedItems::keyAt) - .map(adapter::getItem) - .map(manga -> { - manga.favorite = false; - return manga; - }) + .doOnNext(manga -> manga.favorite = false) .toList() .flatMap(mangas -> db.insertMangas(mangas).createObservable()) .subscribe()); diff --git a/app/src/main/java/eu/kanade/mangafeed/ui/manga/info/MangaInfoFragment.java b/app/src/main/java/eu/kanade/mangafeed/ui/manga/info/MangaInfoFragment.java index 746a9c899e..b6e4146195 100644 --- a/app/src/main/java/eu/kanade/mangafeed/ui/manga/info/MangaInfoFragment.java +++ b/app/src/main/java/eu/kanade/mangafeed/ui/manga/info/MangaInfoFragment.java @@ -8,9 +8,12 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; +import com.bumptech.glide.load.model.LazyHeaders; + import butterknife.Bind; import butterknife.ButterKnife; import eu.kanade.mangafeed.R; +import eu.kanade.mangafeed.data.cache.CoverCache; import eu.kanade.mangafeed.data.database.models.Manga; import eu.kanade.mangafeed.ui.base.fragment.BaseRxFragment; import nucleus.factory.RequiresPresenter; @@ -62,8 +65,15 @@ public class MangaInfoFragment extends BaseRxFragment { setFavoriteText(manga.favorite); - getPresenter().coverCache.loadOrFetchInto(mCover, - manga.thumbnail_url, getPresenter().source.getGlideHeaders()); + if (mCover.getDrawable() == null) { + CoverCache coverCache = getPresenter().coverCache; + LazyHeaders headers = getPresenter().source.getGlideHeaders(); + if (manga.favorite) { + coverCache.saveAndLoadFromCache(mCover, manga.thumbnail_url, headers); + } else { + coverCache.loadFromNetwork(mCover, manga.thumbnail_url, headers); + } + } }