Moved edit cover to library | Updated manga info view | Updated catalogue

grid
This commit is contained in:
NoodleMage
2016-02-14 14:00:44 +01:00
parent 5c329d2314
commit 3da613dedb
54 changed files with 443 additions and 399 deletions

View File

@ -4,6 +4,8 @@ import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import com.mikepenz.iconics.view.IconicsImageView;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
@ -13,7 +15,7 @@ public class CatalogueGridHolder extends CatalogueHolder {
@Bind(R.id.title) TextView title;
@Bind(R.id.thumbnail) ImageView thumbnail;
@Bind(R.id.favorite_sticker) ImageView favoriteSticker;
@Bind(R.id.favorite_sticker) IconicsImageView favoriteSticker;
public CatalogueGridHolder(View view, CatalogueAdapter adapter, OnListItemClickListener listener) {
super(view, adapter, listener);
@ -23,7 +25,10 @@ public class CatalogueGridHolder extends CatalogueHolder {
@Override
public void onSetValues(Manga manga, CataloguePresenter presenter) {
title.setText(manga.title);
// Set visibility of in library icon.
favoriteSticker.setVisibility(manga.favorite ? View.VISIBLE : View.GONE);
// Set alpha of thumbnail.
thumbnail.setAlpha(manga.favorite ? 0.3f : 1.0f);
setImage(manga, presenter);
}

View File

@ -4,7 +4,15 @@ import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.*;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
@ -14,8 +22,6 @@ import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
import nucleus.factory.RequiresPresenter;
import rx.Subscription;
import java.util.List;
@RequiresPresenter(DownloadPresenter.class)
public class DownloadFragment extends BaseRxFragment<DownloadPresenter> {

View File

@ -1,6 +1,12 @@
package eu.kanade.tachiyomi.ui.download;
import android.os.Bundle;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject;
import eu.kanade.tachiyomi.data.download.DownloadManager;
import eu.kanade.tachiyomi.data.download.model.Download;
import eu.kanade.tachiyomi.data.download.model.DownloadQueue;
@ -12,21 +18,15 @@ import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import timber.log.Timber;
import javax.inject.Inject;
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
public class DownloadPresenter extends BasePresenter<DownloadFragment> {
public final static int GET_DOWNLOAD_QUEUE = 1;
@Inject DownloadManager downloadManager;
private DownloadQueue downloadQueue;
private Subscription statusSubscription;
private Subscription pageProgressSubscription;
private HashMap<Download, Subscription> progressSubscriptions;
public final static int GET_DOWNLOAD_QUEUE = 1;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);

View File

@ -64,7 +64,6 @@ public class LibraryCategoryAdapter extends FlexibleAdapter<LibraryHolder, Manga
final LibraryPresenter presenter = ((LibraryFragment) fragment.getParentFragment()).getPresenter();
final Manga manga = getItem(position);
holder.onSetValues(manga, presenter);
//When user scrolls this bind the correct selection status
holder.itemView.setActivated(isSelected(position));
}

View File

@ -47,6 +47,8 @@ public class LibraryCategoryFragment extends BaseFragment
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedState) {
// Inflate the layout for this fragment
@ -86,7 +88,10 @@ public class LibraryCategoryFragment extends BaseFragment
adapter.updateDataSet();
});
return view;
}
@Override
@ -165,15 +170,16 @@ public class LibraryCategoryFragment extends BaseFragment
private void toggleSelection(int position) {
LibraryFragment f = getLibraryFragment();
adapter.toggleSelection(position, false);
f.getPresenter().setSelection(adapter.getItem(position), adapter.isSelected(position));
int count = f.getPresenter().selectedMangas.size();
if (count == 0) {
f.destroyActionModeIfNeeded();
} else {
}
else {
f.setContextTitle(count);
f.setVisibilityOfCoverEdit(count);
f.invalidateActionMode();
}
}

View File

@ -1,6 +1,8 @@
package eu.kanade.tachiyomi.ui.library;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.design.widget.AppBarLayout;
@ -20,6 +22,8 @@ import com.afollestad.materialdialogs.MaterialDialog;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -30,11 +34,13 @@ import eu.davidea.flexibleadapter.FlexibleAdapter;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Category;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.data.io.IOHandler;
import eu.kanade.tachiyomi.data.sync.LibraryUpdateService;
import eu.kanade.tachiyomi.event.LibraryMangasEvent;
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
import eu.kanade.tachiyomi.ui.library.category.CategoryActivity;
import eu.kanade.tachiyomi.ui.main.MainActivity;
import eu.kanade.tachiyomi.util.ToastUtil;
import icepick.State;
import nucleus.factory.RequiresPresenter;
@ -42,17 +48,25 @@ import nucleus.factory.RequiresPresenter;
public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
implements ActionMode.Callback {
@Bind(R.id.view_pager) ViewPager viewPager;
private TabLayout tabs;
private AppBarLayout appBar;
private static final int REQUEST_IMAGE_OPEN = 101;
protected LibraryAdapter adapter;
private ActionMode actionMode;
@Bind(R.id.view_pager) ViewPager viewPager;
@State int activeCategory;
@State String query = "";
private TabLayout tabs;
private AppBarLayout appBar;
private ActionMode actionMode;
private Manga selectedCoverManga;
public static LibraryFragment newInstance() {
return new LibraryFragment();
}
@ -187,6 +201,11 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
actionMode.setTitle(getString(R.string.label_selected, count));
}
public void setVisibilityOfCoverEdit(int count) {
// If count = 1 display edit button
actionMode.getMenu().findItem(R.id.action_edit_cover).setVisible((count == 1));
}
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.library_selection, menu);
@ -202,6 +221,11 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.action_edit_cover:
changeSelectedCover(getPresenter().selectedMangas);
rebuildAdapter();
destroyActionModeIfNeeded();
return true;
case R.id.action_move_to_category:
moveMangasToCategories(getPresenter().selectedMangas);
return true;
@ -213,6 +237,15 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
return false;
}
/**
* TODO workaround. Covers won't refresh any other way.
*/
public void rebuildAdapter() {
adapter = new LibraryAdapter(getChildFragmentManager());
viewPager.setAdapter(adapter);
tabs.setupWithViewPager(viewPager);
}
@Override
public void onDestroyActionMode(ActionMode mode) {
adapter.setSelectionMode(FlexibleAdapter.MODE_SINGLE);
@ -226,6 +259,53 @@ public class LibraryFragment extends BaseRxFragment<LibraryPresenter>
}
}
private void changeSelectedCover(List<Manga> mangas) {
if (mangas.size() == 1) {
selectedCoverManga = mangas.get(0);
if (selectedCoverManga.favorite) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
getString(R.string.file_select_cover)), REQUEST_IMAGE_OPEN);
} else {
ToastUtil.showShort(getContext(), R.string.notification_first_add_to_library);
}
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK) {
switch (requestCode) {
case (REQUEST_IMAGE_OPEN):
if (selectedCoverManga != null) {
// Get the file's content URI from the incoming Intent
Uri selectedImageUri = data.getData();
// Convert to absolute path to prevent FileNotFoundException
String result = IOHandler.getFilePath(selectedImageUri,
getContext().getContentResolver(), getContext());
// Get file from filepath
File picture = new File(result != null ? result : "");
try {
// Update cover to selected file, show error if something went wrong
if (!getPresenter().editCoverWithLocalFile(picture, selectedCoverManga))
ToastUtil.showShort(getContext(), R.string.notification_manga_update_failed);
} catch (IOException e) {
e.printStackTrace();
}
}
break;
}
}
}
private void moveMangasToCategories(List<Manga> mangas) {
new MaterialDialog.Builder(getActivity())
.title(R.string.action_move_category)

View File

@ -50,4 +50,6 @@ public class LibraryHolder extends FlexibleViewHolder {
}
}
}

View File

@ -5,6 +5,8 @@ import android.util.Pair;
import org.greenrobot.eventbus.EventBus;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -26,18 +28,15 @@ import rx.subjects.BehaviorSubject;
public class LibraryPresenter extends BasePresenter<LibraryFragment> {
private static final int GET_LIBRARY = 1;
protected List<Category> categories;
protected List<Manga> selectedMangas;
protected BehaviorSubject<String> searchSubject;
@Inject DatabaseHelper db;
@Inject PreferencesHelper preferences;
@Inject CoverCache coverCache;
@Inject SourceManager sourceManager;
protected List<Category> categories;
protected List<Manga> selectedMangas;
protected BehaviorSubject<String> searchSubject;
private static final int GET_LIBRARY = 1;
@Override
protected void onCreate(Bundle savedState) {
super.onCreate(savedState);
@ -141,4 +140,18 @@ public class LibraryPresenter extends BasePresenter<LibraryFragment> {
db.setMangaCategories(mc, mangas);
}
/**
* Update cover with local file
*/
public boolean editCoverWithLocalFile(File file, Manga manga) throws IOException {
if (!manga.initialized)
return false;
if (manga.favorite) {
coverCache.copyToLocalCache(manga.thumbnail_url, file);
return true;
}
return false;
}
}

View File

@ -8,12 +8,22 @@ import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.*;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
import android.widget.ImageView;
import com.afollestad.materialdialogs.MaterialDialog;
import java.util.ArrayList;
import java.util.List;
import butterknife.Bind;
import butterknife.ButterKnife;
import com.afollestad.materialdialogs.MaterialDialog;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.database.models.Chapter;
import eu.kanade.tachiyomi.data.database.models.Manga;
@ -31,9 +41,6 @@ import rx.Subscription;
import rx.android.schedulers.AndroidSchedulers;
import rx.schedulers.Schedulers;
import java.util.ArrayList;
import java.util.List;
@RequiresPresenter(ChaptersPresenter.class)
public class ChaptersFragment extends BaseRxFragment<ChaptersPresenter> implements
ActionMode.Callback, FlexibleViewHolder.OnListItemClickListener {

View File

@ -7,6 +7,12 @@ import android.view.View;
import android.widget.PopupMenu;
import android.widget.RelativeLayout;
import android.widget.TextView;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Date;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
@ -16,30 +22,21 @@ import eu.kanade.tachiyomi.data.download.model.Download;
import eu.kanade.tachiyomi.ui.base.adapter.FlexibleViewHolder;
import rx.Observable;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.Date;
public class ChaptersHolder extends FlexibleViewHolder {
private final ChaptersAdapter adapter;
private final int readColor;
private final int unreadColor;
private final DecimalFormat decimalFormat;
private final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
@Bind(R.id.chapter_title) TextView title;
@Bind(R.id.download_text) TextView downloadText;
@Bind(R.id.chapter_menu) RelativeLayout chapterMenu;
@Bind(R.id.chapter_pages) TextView pages;
@Bind(R.id.chapter_date) TextView date;
private Context context;
private final ChaptersAdapter adapter;
private Chapter item;
private final int readColor;
private final int unreadColor;
private final DecimalFormat decimalFormat;
private final DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);
public ChaptersHolder(View view, ChaptersAdapter adapter, OnListItemClickListener listener) {
super(view, adapter, listener);
this.adapter = adapter;

View File

@ -1,8 +1,5 @@
package eu.kanade.tachiyomi.ui.manga.info;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.v4.content.ContextCompat;
@ -10,32 +7,22 @@ import android.support.v4.widget.SwipeRefreshLayout;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.TextView;
import com.bumptech.glide.load.model.LazyHeaders;
import com.mikepenz.google_material_typeface_library.GoogleMaterial;
import com.mikepenz.iconics.IconicsDrawable;
import java.io.File;
import java.io.IOException;
import butterknife.Bind;
import butterknife.ButterKnife;
import eu.kanade.tachiyomi.R;
import eu.kanade.tachiyomi.data.cache.CoverCache;
import eu.kanade.tachiyomi.data.database.models.Manga;
import eu.kanade.tachiyomi.data.io.IOHandler;
import eu.kanade.tachiyomi.data.source.base.Source;
import eu.kanade.tachiyomi.ui.base.fragment.BaseRxFragment;
import eu.kanade.tachiyomi.util.ToastUtil;
import nucleus.factory.RequiresPresenter;
@RequiresPresenter(MangaInfoPresenter.class)
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
private static final int REQUEST_IMAGE_OPEN = 101;
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
@Bind(R.id.manga_artist) TextView artist;
@Bind(R.id.manga_author) TextView author;
@ -45,8 +32,8 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
@Bind(R.id.manga_source) TextView source;
@Bind(R.id.manga_summary) TextView description;
@Bind(R.id.manga_cover) ImageView cover;
@Bind(R.id.action_favorite) Button favoriteBtn;
@Bind(R.id.fab_edit) FloatingActionButton fabEdit;
@Bind(R.id.backdrop) ImageView backdrop;
@Bind(R.id.fab_favorite) FloatingActionButton fabFavorite;
public static MangaInfoFragment newInstance() {
return new MangaInfoFragment();
@ -65,10 +52,7 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
View view = inflater.inflate(R.layout.fragment_manga_info, container, false);
ButterKnife.bind(this, view);
// Set listener.
fabEdit.setOnClickListener(v -> selectImage());
favoriteBtn.setOnClickListener(v -> getPresenter().toggleFavorite());
fabFavorite.setOnClickListener(v -> getPresenter().toggleFavorite());
swipeRefresh.setOnRefreshListener(this::fetchMangaFromSource);
@ -101,7 +85,7 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
status.setText(manga.getStatus(getActivity()));
description.setText(manga.description);
setFavoriteText(manga.favorite);
setFavoriteDrawable(manga.favorite);
CoverCache coverCache = getPresenter().coverCache;
LazyHeaders headers = getPresenter().source.getGlideHeaders();
@ -112,14 +96,23 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
coverCache.loadFromNetwork(cover, manga.thumbnail_url, headers);
}
}
if (manga.thumbnail_url != null && backdrop.getDrawable() == null) {
if (manga.favorite) {
coverCache.saveOrLoadFromCache(backdrop, manga.thumbnail_url, headers);
} else {
coverCache.loadFromNetwork(backdrop, manga.thumbnail_url, headers);
}
}
}
public void setChapterCount(int count) {
chapterCount.setText(String.valueOf(count));
}
private void setFavoriteText(boolean isFavorite) {
favoriteBtn.setText(!isFavorite ? R.string.add_to_library : R.string.remove_from_library);
private void setFavoriteDrawable(boolean isFavorite) {
fabFavorite.setImageDrawable(ContextCompat.getDrawable(getContext(), isFavorite ?
R.drawable.ic_bookmark_white_24dp :
R.drawable.ic_bookmark_border_white_24dp));
}
private void fetchMangaFromSource() {
@ -127,43 +120,6 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
getPresenter().fetchMangaFromSource();
}
private void selectImage() {
if (getPresenter().getManga().favorite) {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent,
getString(R.string.file_select_cover)), REQUEST_IMAGE_OPEN);
} else {
ToastUtil.showShort(getContext(), R.string.notification_first_add_to_library);
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_IMAGE_OPEN) {
// Get the file's content URI from the incoming Intent
Uri selectedImageUri = data.getData();
// Convert to absolute path to prevent FileNotFoundException
String result = IOHandler.getFilePath(selectedImageUri,
getContext().getContentResolver(), getContext());
// Get file from filepath
File picture = new File(result != null ? result : "");
try {
// Update cover to selected file, show error if something went wrong
if (!getPresenter().editCoverWithLocalFile(picture, cover))
ToastUtil.showShort(getContext(), R.string.notification_manga_update_failed);
} catch (IOException e) {
e.printStackTrace();
}
}
}
public void onFetchMangaDone() {
setRefreshing(false);

View File

@ -1,14 +1,10 @@
package eu.kanade.tachiyomi.ui.manga.info;
import android.os.Bundle;
import android.widget.ImageView;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import java.io.File;
import java.io.IOException;
import javax.inject.Inject;
import eu.kanade.tachiyomi.data.cache.CoverCache;
@ -135,20 +131,7 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
refreshManga();
}
/**
* Update cover with local file
*/
public boolean editCoverWithLocalFile(File file, ImageView imageView) throws IOException {
if (!manga.initialized)
return false;
if (manga.favorite) {
coverCache.copyToLocalCache(manga.thumbnail_url, file);
coverCache.saveOrLoadFromCache(imageView, manga.thumbnail_url, source.getGlideHeaders());
return true;
}
return false;
}
private void onMangaFavoriteChange(boolean isFavorite) {
if (isFavorite) {

View File

@ -65,7 +65,6 @@ public class RecentChaptersFragment extends BaseRxFragment<RecentChaptersPresent
@Override
public void onListItemLongClick(int position) {
}
protected void openChapter(MangaChapter chapter) {

View File

@ -5,6 +5,9 @@ import android.content.res.TypedArray;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.widget.ImageView;
import eu.kanade.tachiyomi.R;
public class AutofitRecyclerView extends RecyclerView {