Browse Source

Improve the use and caching of the covers' cache. Use restartables in LibraryPresenter

inorichi 9 years ago
parent
commit
54a715640d

+ 30 - 28
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<File>() {
                     @Override
                     public void onResourceReady(File resource, GlideAnimation<? super File> 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);
-        }
-    }
-
-    // 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);
+            save(thumbnailUrl, headers, imageView);
         }
     }
 
-    // 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)

+ 0 - 1
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);
     }
 

+ 15 - 5
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<Manga> implements Filterable {
 
     List<Manga> 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<Manga> list) {
@@ -57,9 +60,16 @@ public class LibraryAdapter extends EasyAdapter<Manga> implements Filterable {
 
         @Override
         public void publishResults(CharSequence constraint, FilterResults results) {
-            setItems((List<Manga >) results.values);
+            setItems((List<Manga>) 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;
+    }
 }

+ 13 - 7
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<LibraryPresenter> {
@@ -31,10 +33,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
     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<LibraryPresenter> {
     }
 
     private void createAdapter() {
-        adapter = new LibraryAdapter(getActivity());
+        adapter = new LibraryAdapter(this);
         grid.setAdapter(adapter);
     }
 
@@ -136,7 +135,7 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter> {
             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<LibraryPresenter> {
         });
     }
 
+    private Observable<Manga> getSelectedMangas() {
+        SparseBooleanArray checkedItems = grid.getCheckedItemPositions();
+        return Observable.range(0, checkedItems.size())
+                .map(checkedItems::keyAt)
+                .map(adapter::getItem);
+    }
+
 }

+ 5 - 8
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<Manga> {
 
     @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<Manga> {
         } 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());
     }
 
 }

+ 16 - 31
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<LibraryFragment> {
 
     @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);
-    }
-
-    @Override
-    protected void onTakeView(LibraryFragment view) {
-        super.onTakeView(view);
-        getFavoriteMangas();
-    }
 
-    public void getFavoriteMangas() {
-        if (mFavoriteMangasSubscription != null)
-            return;
+        restartableLatestCache(GET_MANGAS,
+                () -> db.getMangasWithUnread().createObservable()
+                        .subscribeOn(Schedulers.io())
+                        .observeOn(AndroidSchedulers.mainThread()),
+                LibraryFragment::onNextMangas);
 
-        add(mFavoriteMangasSubscription = db.getMangasWithUnread().createObservable()
-                .subscribeOn(Schedulers.io())
-                .observeOn(AndroidSchedulers.mainThread())
-                .compose(deliverLatestCache())
-                .subscribe(this.split(LibraryFragment::onNextMangas)));
+        start(GET_MANGAS);
     }
 
-    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;
-                })
+    public void deleteMangas(Observable<Manga> selectedMangas) {
+        add(selectedMangas
+                .subscribeOn(Schedulers.io())
+                .doOnNext(manga -> manga.favorite = false)
                 .toList()
                 .flatMap(mangas -> db.insertMangas(mangas).createObservable())
                 .subscribe());

+ 12 - 2
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<MangaInfoPresenter> {
 
         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);
+            }
+        }
 
     }