mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-03 23:58:55 +01:00 
			
		
		
		
	Merge pull request #91 from NoodleMage/change_cover
Can now manually set cover pictures. #79
This commit is contained in:
		@@ -130,12 +130,15 @@ dependencies {
 | 
			
		||||
    compile('com.mikepenz:materialdrawer:4.6.4@aar') {
 | 
			
		||||
        transitive = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //Google material icons SVG.
 | 
			
		||||
    compile 'com.mikepenz:google-material-typeface:2.1.0.1.original@aar'
 | 
			
		||||
 | 
			
		||||
    compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') {
 | 
			
		||||
        transitive = true
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    testCompile 'junit:junit:4.12'
 | 
			
		||||
    testCompile 'org.assertj:assertj-core:2.3.0'
 | 
			
		||||
    testCompile "org.mockito:mockito-core:$MOCKITO_VERSION"
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@ import com.bumptech.glide.load.model.GlideUrl;
 | 
			
		||||
import com.bumptech.glide.load.model.LazyHeaders;
 | 
			
		||||
import com.bumptech.glide.request.animation.GlideAnimation;
 | 
			
		||||
import com.bumptech.glide.request.target.SimpleTarget;
 | 
			
		||||
import com.bumptech.glide.signature.StringSignature;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
@@ -119,7 +120,7 @@ public class CoverCache {
 | 
			
		||||
     * @param source       the cover image.
 | 
			
		||||
     * @throws IOException exception returned
 | 
			
		||||
     */
 | 
			
		||||
    private void copyToLocalCache(String thumbnailUrl, File source) throws IOException {
 | 
			
		||||
    public void copyToLocalCache(String thumbnailUrl, File source) throws IOException {
 | 
			
		||||
        // Create cache directory if needed.
 | 
			
		||||
        createCacheDir();
 | 
			
		||||
 | 
			
		||||
@@ -200,11 +201,12 @@ public class CoverCache {
 | 
			
		||||
     * @param imageView imageView where picture should be displayed.
 | 
			
		||||
     * @param file      file to load. Must exist!.
 | 
			
		||||
     */
 | 
			
		||||
    private void loadFromCache(ImageView imageView, File file) {
 | 
			
		||||
    public void loadFromCache(ImageView imageView, File file) {
 | 
			
		||||
        Glide.with(context)
 | 
			
		||||
                .load(file)
 | 
			
		||||
                .diskCacheStrategy(DiskCacheStrategy.RESULT)
 | 
			
		||||
                .centerCrop()
 | 
			
		||||
                .signature(new StringSignature(String.valueOf(file.lastModified())))
 | 
			
		||||
                .into(imageView);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,6 @@ public interface AppComponent {
 | 
			
		||||
    void inject(LibraryUpdateService libraryUpdateService);
 | 
			
		||||
    void inject(DownloadService downloadService);
 | 
			
		||||
    void inject(UpdateMangaSyncService updateMangaSyncService);
 | 
			
		||||
 | 
			
		||||
    Application application();
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										110
									
								
								app/src/main/java/eu/kanade/tachiyomi/io/IOHandler.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										110
									
								
								app/src/main/java/eu/kanade/tachiyomi/io/IOHandler.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,110 @@
 | 
			
		||||
package eu.kanade.tachiyomi.io;
 | 
			
		||||
 | 
			
		||||
import android.content.ContentResolver;
 | 
			
		||||
import android.content.Context;
 | 
			
		||||
import android.database.Cursor;
 | 
			
		||||
import android.net.Uri;
 | 
			
		||||
import android.os.Build;
 | 
			
		||||
import android.os.ParcelFileDescriptor;
 | 
			
		||||
import android.provider.DocumentsContract;
 | 
			
		||||
import android.provider.MediaStore;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.FileDescriptor;
 | 
			
		||||
import java.io.FileInputStream;
 | 
			
		||||
import java.io.FileOutputStream;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
public class IOHandler {
 | 
			
		||||
    /**
 | 
			
		||||
     * Get full filepath of build in Android File picker.
 | 
			
		||||
     * If Google Drive (or other Cloud service) throw exception and download before loading
 | 
			
		||||
     */
 | 
			
		||||
    public static String getFilePath(Uri uri, ContentResolver resolver, Context context) {
 | 
			
		||||
        try {
 | 
			
		||||
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
 | 
			
		||||
                String filePath = "";
 | 
			
		||||
                String wholeID = DocumentsContract.getDocumentId(uri);
 | 
			
		||||
 | 
			
		||||
                //Ugly work around. In sdk version Kitkat or higher external getDocumentId request will have no content://
 | 
			
		||||
                if (wholeID.split(":").length == 1)
 | 
			
		||||
                    throw new IllegalArgumentException();
 | 
			
		||||
 | 
			
		||||
                // Split at colon, use second item in the array
 | 
			
		||||
                String id = wholeID.split(":")[1];
 | 
			
		||||
 | 
			
		||||
                String[] column = {MediaStore.Images.Media.DATA};
 | 
			
		||||
 | 
			
		||||
                // where id is equal to
 | 
			
		||||
                String sel = MediaStore.Images.Media._ID + "=?";
 | 
			
		||||
 | 
			
		||||
                Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
 | 
			
		||||
                        column, sel, new String[]{id}, null);
 | 
			
		||||
 | 
			
		||||
                int columnIndex = cursor != null ? cursor.getColumnIndex(column[0]) : 0;
 | 
			
		||||
 | 
			
		||||
                if (cursor != null ? cursor.moveToFirst() : false) {
 | 
			
		||||
                    filePath = cursor.getString(columnIndex);
 | 
			
		||||
                }
 | 
			
		||||
                cursor.close();
 | 
			
		||||
                return filePath;
 | 
			
		||||
            } else {
 | 
			
		||||
                String[] fields = {MediaStore.Images.Media.DATA};
 | 
			
		||||
 | 
			
		||||
                Cursor cursor = resolver.query(uri, fields, null, null, null);
 | 
			
		||||
 | 
			
		||||
                if (cursor == null)
 | 
			
		||||
                    return null;
 | 
			
		||||
 | 
			
		||||
                cursor.moveToFirst();
 | 
			
		||||
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
 | 
			
		||||
                cursor.close();
 | 
			
		||||
 | 
			
		||||
                return path;
 | 
			
		||||
            }
 | 
			
		||||
        } catch (IllegalArgumentException e) {
 | 
			
		||||
            //This exception is thrown when Google Drive. Try to download file
 | 
			
		||||
            return downloadMediaAndReturnPath(uri, resolver, context);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String getTempFilename(Context context) throws IOException {
 | 
			
		||||
        File outputDir = context.getCacheDir();
 | 
			
		||||
        File outputFile = File.createTempFile("temp_cover", "0", outputDir);
 | 
			
		||||
        return outputFile.getAbsolutePath();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static String downloadMediaAndReturnPath(Uri uri, ContentResolver resolver, Context context) {
 | 
			
		||||
        if (uri == null) return null;
 | 
			
		||||
        FileInputStream input = null;
 | 
			
		||||
        FileOutputStream output = null;
 | 
			
		||||
        try {
 | 
			
		||||
            ParcelFileDescriptor pfd = resolver.openFileDescriptor(uri, "r");
 | 
			
		||||
            FileDescriptor fd = pfd != null ? pfd.getFileDescriptor() : null;
 | 
			
		||||
            input = new FileInputStream(fd);
 | 
			
		||||
 | 
			
		||||
            String tempFilename = getTempFilename(context);
 | 
			
		||||
            output = new FileOutputStream(tempFilename);
 | 
			
		||||
 | 
			
		||||
            int read;
 | 
			
		||||
            byte[] bytes = new byte[4096];
 | 
			
		||||
            while ((read = input.read(bytes)) != -1) {
 | 
			
		||||
                output.write(bytes, 0, read);
 | 
			
		||||
            }
 | 
			
		||||
            return tempFilename;
 | 
			
		||||
        } catch (IOException ignored) {
 | 
			
		||||
        } finally {
 | 
			
		||||
            if (input != null) try {
 | 
			
		||||
                input.close();
 | 
			
		||||
            } catch (Exception ignored) {
 | 
			
		||||
            }
 | 
			
		||||
            if (output != null) try {
 | 
			
		||||
                output.close();
 | 
			
		||||
            } catch (Exception ignored) {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        return null;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@@ -1,6 +1,11 @@
 | 
			
		||||
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;
 | 
			
		||||
import android.support.v4.widget.SwipeRefreshLayout;
 | 
			
		||||
import android.view.LayoutInflater;
 | 
			
		||||
import android.view.View;
 | 
			
		||||
@@ -10,6 +15,11 @@ 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;
 | 
			
		||||
@@ -17,14 +27,16 @@ 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.source.base.Source;
 | 
			
		||||
import eu.kanade.tachiyomi.io.IOHandler;
 | 
			
		||||
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;
 | 
			
		||||
    @Bind(R.id.manga_chapters) TextView chapterCount;
 | 
			
		||||
@@ -33,9 +45,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;
 | 
			
		||||
 | 
			
		||||
    public static MangaInfoFragment newInstance() {
 | 
			
		||||
        return new MangaInfoFragment();
 | 
			
		||||
@@ -54,9 +65,20 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
 | 
			
		||||
        View view = inflater.inflate(R.layout.fragment_manga_info, container, false);
 | 
			
		||||
        ButterKnife.bind(this, view);
 | 
			
		||||
 | 
			
		||||
        favoriteBtn.setOnClickListener(v -> {
 | 
			
		||||
            getPresenter().toggleFavorite();
 | 
			
		||||
        });
 | 
			
		||||
        //Create edit drawable with size 24dp (google guidelines)
 | 
			
		||||
        IconicsDrawable edit = new IconicsDrawable(this.getContext())
 | 
			
		||||
                .icon(GoogleMaterial.Icon.gmd_edit)
 | 
			
		||||
                .color(ContextCompat.getColor(this.getContext(), R.color.white))
 | 
			
		||||
                .sizeDp(24);
 | 
			
		||||
 | 
			
		||||
        // Update image of fab buttons
 | 
			
		||||
        fabEdit.setImageDrawable(edit);
 | 
			
		||||
 | 
			
		||||
        // Set listener.
 | 
			
		||||
        fabEdit.setOnClickListener(v -> MangaInfoFragment.this.selectImage());
 | 
			
		||||
 | 
			
		||||
        favoriteBtn.setOnClickListener(v -> getPresenter().toggleFavorite());
 | 
			
		||||
 | 
			
		||||
        swipeRefresh.setOnRefreshListener(this::fetchMangaFromSource);
 | 
			
		||||
 | 
			
		||||
        return view;
 | 
			
		||||
@@ -71,6 +93,12 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Set the info of the manga
 | 
			
		||||
     *
 | 
			
		||||
     * @param manga       manga object containing information about manga
 | 
			
		||||
     * @param mangaSource the source of the manga
 | 
			
		||||
     */
 | 
			
		||||
    private void setMangaInfo(Manga manga, Source mangaSource) {
 | 
			
		||||
        artist.setText(manga.artist);
 | 
			
		||||
        author.setText(manga.author);
 | 
			
		||||
@@ -99,7 +127,7 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
 | 
			
		||||
        chapterCount.setText(String.valueOf(count));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setFavoriteText(boolean isFavorite) {
 | 
			
		||||
    private void setFavoriteText(boolean isFavorite) {
 | 
			
		||||
        favoriteBtn.setText(!isFavorite ? R.string.add_to_library : R.string.remove_from_library);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -108,6 +136,45 @@ 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) {
 | 
			
		||||
            if (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, this.getContext().getContentResolver(), this.getContext());
 | 
			
		||||
 | 
			
		||||
                // Get file from filepath
 | 
			
		||||
                File picture = new File(result != null ? result : "");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                try {
 | 
			
		||||
                    // Update cover to selected file
 | 
			
		||||
                    getPresenter().editCoverWithLocalFile(picture, cover);
 | 
			
		||||
 | 
			
		||||
                } catch (IOException e) {
 | 
			
		||||
                    e.printStackTrace();
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void onFetchMangaDone() {
 | 
			
		||||
        setRefreshing(false);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,10 @@
 | 
			
		||||
package eu.kanade.tachiyomi.ui.manga.info;
 | 
			
		||||
 | 
			
		||||
import android.os.Bundle;
 | 
			
		||||
import android.widget.ImageView;
 | 
			
		||||
 | 
			
		||||
import java.io.File;
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
 | 
			
		||||
import javax.inject.Inject;
 | 
			
		||||
 | 
			
		||||
@@ -19,17 +23,42 @@ import rx.schedulers.Schedulers;
 | 
			
		||||
 | 
			
		||||
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
 | 
			
		||||
 | 
			
		||||
    @Inject DatabaseHelper db;
 | 
			
		||||
    @Inject SourceManager sourceManager;
 | 
			
		||||
    @Inject CoverCache coverCache;
 | 
			
		||||
    
 | 
			
		||||
    protected Source source;
 | 
			
		||||
    private Manga manga;
 | 
			
		||||
    private int count = -1;
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * The id of the restartable.
 | 
			
		||||
     */
 | 
			
		||||
    private static final int GET_MANGA = 1;
 | 
			
		||||
    /**
 | 
			
		||||
     * The id of the restartable.
 | 
			
		||||
     */
 | 
			
		||||
    private static final int GET_CHAPTER_COUNT = 2;
 | 
			
		||||
    /**
 | 
			
		||||
     * The id of the restartable.
 | 
			
		||||
     */
 | 
			
		||||
    private static final int FETCH_MANGA_INFO = 3;
 | 
			
		||||
    /**
 | 
			
		||||
     * Source information
 | 
			
		||||
     */
 | 
			
		||||
    protected Source source;
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to connect to database
 | 
			
		||||
     */
 | 
			
		||||
    @Inject DatabaseHelper db;
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to connect to different manga sources
 | 
			
		||||
     */
 | 
			
		||||
    @Inject SourceManager sourceManager;
 | 
			
		||||
    /**
 | 
			
		||||
     * Used to connect to cache
 | 
			
		||||
     */
 | 
			
		||||
    @Inject CoverCache coverCache;
 | 
			
		||||
    /**
 | 
			
		||||
     * Selected manga information
 | 
			
		||||
     */
 | 
			
		||||
    private Manga manga;
 | 
			
		||||
    /**
 | 
			
		||||
     * Count of chapters
 | 
			
		||||
     */
 | 
			
		||||
    private int count = -1;
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    protected void onCreate(Bundle savedState) {
 | 
			
		||||
@@ -39,22 +68,29 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
 | 
			
		||||
            onProcessRestart();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Update manga cache
 | 
			
		||||
        restartableLatestCache(GET_MANGA,
 | 
			
		||||
                () -> Observable.just(manga),
 | 
			
		||||
                (view, manga) -> view.onNextManga(manga, source));
 | 
			
		||||
 | 
			
		||||
        // Update chapter count
 | 
			
		||||
        restartableLatestCache(GET_CHAPTER_COUNT,
 | 
			
		||||
                () -> Observable.just(count),
 | 
			
		||||
                MangaInfoFragment::setChapterCount);
 | 
			
		||||
 | 
			
		||||
        // Fetch manga info from source
 | 
			
		||||
        restartableFirst(FETCH_MANGA_INFO,
 | 
			
		||||
                this::fetchMangaObs,
 | 
			
		||||
                (view, manga) -> view.onFetchMangaDone(),
 | 
			
		||||
                (view, error) -> view.onFetchMangaError());
 | 
			
		||||
 | 
			
		||||
        // onEventMainThread receives an event thanks to this line.
 | 
			
		||||
        registerForStickyEvents();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Called when savedState not null
 | 
			
		||||
     */
 | 
			
		||||
    private void onProcessRestart() {
 | 
			
		||||
        stop(GET_MANGA);
 | 
			
		||||
        stop(GET_CHAPTER_COUNT);
 | 
			
		||||
@@ -82,6 +118,9 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Fetch manga info from source
 | 
			
		||||
     */
 | 
			
		||||
    public void fetchMangaFromSource() {
 | 
			
		||||
        if (isUnsubscribed(FETCH_MANGA_INFO)) {
 | 
			
		||||
            start(FETCH_MANGA_INFO);
 | 
			
		||||
@@ -107,6 +146,16 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
 | 
			
		||||
        refreshManga();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * Update cover with local file
 | 
			
		||||
     */
 | 
			
		||||
    public void editCoverWithLocalFile(File file, ImageView imageView) throws IOException {
 | 
			
		||||
        if (manga.favorite) {
 | 
			
		||||
            coverCache.copyToLocalCache(manga.thumbnail_url, file);
 | 
			
		||||
            coverCache.loadFromCache(imageView, file);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private void onMangaFavoriteChange(boolean isFavorite) {
 | 
			
		||||
        if (isFavorite) {
 | 
			
		||||
            coverCache.save(manga.thumbnail_url, source.getGlideHeaders());
 | 
			
		||||
@@ -115,8 +164,12 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public Manga getManga() {
 | 
			
		||||
        return manga;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Used to refresh the view
 | 
			
		||||
    private void refreshManga() {
 | 
			
		||||
    protected void refreshManga() {
 | 
			
		||||
        start(GET_MANGA);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,10 +1,11 @@
 | 
			
		||||
<?xml version="1.0" encoding="utf-8"?>
 | 
			
		||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
    xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
    android:layout_width="match_parent"
 | 
			
		||||
    android:layout_height="match_parent"
 | 
			
		||||
    android:orientation="vertical"
 | 
			
		||||
    tools:context="eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment">
 | 
			
		||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 | 
			
		||||
                xmlns:app="http://schemas.android.com/apk/res-auto"
 | 
			
		||||
                xmlns:tools="http://schemas.android.com/tools"
 | 
			
		||||
                android:layout_width="match_parent"
 | 
			
		||||
                android:layout_height="match_parent"
 | 
			
		||||
                android:orientation="vertical"
 | 
			
		||||
                tools:context="eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment">
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    <!-- It seems I have to wrap everything in SwipeRefreshLayout because it always take the entire height
 | 
			
		||||
@@ -16,8 +17,8 @@
 | 
			
		||||
    <android.support.v4.widget.SwipeRefreshLayout
 | 
			
		||||
        android:id="@+id/swipe_refresh"
 | 
			
		||||
        android:layout_width="match_parent"
 | 
			
		||||
        android:orientation="vertical"
 | 
			
		||||
        android:layout_height="match_parent">
 | 
			
		||||
        android:layout_height="match_parent"
 | 
			
		||||
        android:orientation="vertical">
 | 
			
		||||
 | 
			
		||||
        <ScrollView
 | 
			
		||||
            android:layout_width="match_parent"
 | 
			
		||||
@@ -50,7 +51,7 @@
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:scaleType="fitXY"
 | 
			
		||||
                            android:visibility="visible" />
 | 
			
		||||
                            android:visibility="visible"/>
 | 
			
		||||
 | 
			
		||||
                    </RelativeLayout>
 | 
			
		||||
 | 
			
		||||
@@ -72,7 +73,7 @@
 | 
			
		||||
                            android:layout_marginTop="5dp"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:text="@string/author" />
 | 
			
		||||
                            android:text="@string/author"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_author"
 | 
			
		||||
@@ -85,7 +86,7 @@
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:maxLines="1"
 | 
			
		||||
                            android:singleLine="true" />
 | 
			
		||||
                            android:singleLine="true"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_artist_label"
 | 
			
		||||
@@ -97,7 +98,7 @@
 | 
			
		||||
                            android:layout_below="@id/manga_author_label"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:text="@string/artist" />
 | 
			
		||||
                            android:text="@string/artist"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_artist"
 | 
			
		||||
@@ -110,7 +111,7 @@
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:maxLines="1"
 | 
			
		||||
                            android:singleLine="true" />
 | 
			
		||||
                            android:singleLine="true"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_chapters_label"
 | 
			
		||||
@@ -121,7 +122,7 @@
 | 
			
		||||
                            android:layout_below="@id/manga_artist_label"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:text="@string/chapters" />
 | 
			
		||||
                            android:text="@string/chapters"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_chapters"
 | 
			
		||||
@@ -134,7 +135,7 @@
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:maxLines="1"
 | 
			
		||||
                            android:singleLine="true" />
 | 
			
		||||
                            android:singleLine="true"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_status_label"
 | 
			
		||||
@@ -146,7 +147,7 @@
 | 
			
		||||
                            android:layout_below="@id/manga_chapters_label"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:text="@string/status" />
 | 
			
		||||
                            android:text="@string/status"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_status"
 | 
			
		||||
@@ -159,7 +160,7 @@
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:maxLines="1"
 | 
			
		||||
                            android:singleLine="true" />
 | 
			
		||||
                            android:singleLine="true"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_source_label"
 | 
			
		||||
@@ -170,7 +171,7 @@
 | 
			
		||||
                            android:layout_below="@id/manga_status_label"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:text="@string/source" />
 | 
			
		||||
                            android:text="@string/source"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_source"
 | 
			
		||||
@@ -183,7 +184,7 @@
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:maxLines="1"
 | 
			
		||||
                            android:singleLine="true" />
 | 
			
		||||
                            android:singleLine="true"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_genres_label"
 | 
			
		||||
@@ -194,7 +195,7 @@
 | 
			
		||||
                            android:layout_below="@id/manga_source_label"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:text="@string/genres" />
 | 
			
		||||
                            android:text="@string/genres"/>
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_genres"
 | 
			
		||||
@@ -204,7 +205,7 @@
 | 
			
		||||
                            android:layout_below="@id/manga_genres_label"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:singleLine="false" />
 | 
			
		||||
                            android:singleLine="false"/>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                    </RelativeLayout>
 | 
			
		||||
@@ -221,7 +222,7 @@
 | 
			
		||||
                        android:id="@+id/action_favorite"
 | 
			
		||||
                        android:layout_width="match_parent"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:text="@string/add_to_library" />
 | 
			
		||||
                        android:text="@string/add_to_library"/>
 | 
			
		||||
                </LinearLayout>
 | 
			
		||||
 | 
			
		||||
                <LinearLayout
 | 
			
		||||
@@ -238,24 +239,43 @@
 | 
			
		||||
                        android:focusable="false"
 | 
			
		||||
                        android:focusableInTouchMode="false"
 | 
			
		||||
                        android:singleLine="false"
 | 
			
		||||
                        android:text="@string/description" />
 | 
			
		||||
                        android:text="@string/description"/>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                        <TextView
 | 
			
		||||
                            android:id="@+id/manga_summary"
 | 
			
		||||
                            style="@style/manga_detail_text"
 | 
			
		||||
                            android:layout_width="match_parent"
 | 
			
		||||
                            android:layout_height="wrap_content"
 | 
			
		||||
                            android:focusable="false"
 | 
			
		||||
                            android:focusableInTouchMode="false"
 | 
			
		||||
                            android:singleLine="false" />
 | 
			
		||||
                    
 | 
			
		||||
                    <TextView
 | 
			
		||||
                        android:id="@+id/manga_summary"
 | 
			
		||||
                        style="@style/manga_detail_text"
 | 
			
		||||
                        android:layout_width="match_parent"
 | 
			
		||||
                        android:layout_height="wrap_content"
 | 
			
		||||
                        android:focusable="false"
 | 
			
		||||
                        android:focusableInTouchMode="false"
 | 
			
		||||
                        android:singleLine="false"/>
 | 
			
		||||
 | 
			
		||||
                </LinearLayout>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            </LinearLayout>
 | 
			
		||||
 | 
			
		||||
        </ScrollView>
 | 
			
		||||
 | 
			
		||||
    </android.support.v4.widget.SwipeRefreshLayout>
 | 
			
		||||
 | 
			
		||||
</LinearLayout>
 | 
			
		||||
    <LinearLayout
 | 
			
		||||
        android:layout_width="wrap_content"
 | 
			
		||||
        android:layout_height="wrap_content"
 | 
			
		||||
        android:layout_alignParentBottom="true"
 | 
			
		||||
        android:layout_alignParentRight="true"
 | 
			
		||||
        android:layout_margin="10dp"
 | 
			
		||||
        android:gravity="bottom">
 | 
			
		||||
 | 
			
		||||
        <android.support.design.widget.FloatingActionButton
 | 
			
		||||
            android:id="@+id/fab_edit"
 | 
			
		||||
            android:layout_width="wrap_content"
 | 
			
		||||
            android:layout_height="wrap_content"
 | 
			
		||||
            android:layout_gravity="bottom|right"
 | 
			
		||||
            android:layout_margin="@dimen/fab_margin"
 | 
			
		||||
            app:backgroundTint="@color/colorPrimary"
 | 
			
		||||
            app:layout_behavior="eu.kanade.tachiyomi.ui.base.fab.ScrollAwareFABBehavior"/>
 | 
			
		||||
 | 
			
		||||
    </LinearLayout>
 | 
			
		||||
</RelativeLayout>
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
    <color name="primary">@color/colorPrimary</color>
 | 
			
		||||
    <color name="primary_dark">@color/colorPrimaryDark</color>
 | 
			
		||||
    <color name="primary_light">@color/colorPrimaryLight</color>
 | 
			
		||||
    <color name="color_ripple">#E9F1FF</color>
 | 
			
		||||
 | 
			
		||||
    <color name="divider">@color/md_light_dividers</color>
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -205,5 +205,9 @@
 | 
			
		||||
    <string name="notification_no_new_chapters">No new chapters found</string>
 | 
			
		||||
    <string name="notification_new_chapters">New chapters found for:</string>
 | 
			
		||||
    <string name="notification_manga_update_failed">Failed to update manga:</string>
 | 
			
		||||
    <string name="notification_first_add_to_library">Please add the manga to your library before doing this</string>
 | 
			
		||||
 | 
			
		||||
    <!-- File Picker Titles -->
 | 
			
		||||
    <string name="file_select_cover">Select cover image</string>
 | 
			
		||||
 | 
			
		||||
</resources>
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user