Can now manually set cover pictures. #79
Forgot to add IOHandler Removed FAB library now use the internal one. Changed getTimestamp to modification date. Rewrote IOHandler. Fixed Drive Bug. More bug fixes. Tested working for API 16 and 23 Fixed merge bugs
This commit is contained in:
parent
c03495be94
commit
8b52fea602
@ -130,12 +130,15 @@ dependencies {
|
|||||||
compile('com.mikepenz:materialdrawer:4.6.4@aar') {
|
compile('com.mikepenz:materialdrawer:4.6.4@aar') {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Google material icons SVG.
|
||||||
compile 'com.mikepenz:google-material-typeface:2.1.0.1.original@aar'
|
compile 'com.mikepenz:google-material-typeface:2.1.0.1.original@aar'
|
||||||
|
|
||||||
compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') {
|
compile('com.github.afollestad.material-dialogs:core:0.8.5.3@aar') {
|
||||||
transitive = true
|
transitive = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
testCompile 'junit:junit:4.12'
|
testCompile 'junit:junit:4.12'
|
||||||
testCompile 'org.assertj:assertj-core:2.3.0'
|
testCompile 'org.assertj:assertj-core:2.3.0'
|
||||||
testCompile "org.mockito:mockito-core:$MOCKITO_VERSION"
|
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.load.model.LazyHeaders;
|
||||||
import com.bumptech.glide.request.animation.GlideAnimation;
|
import com.bumptech.glide.request.animation.GlideAnimation;
|
||||||
import com.bumptech.glide.request.target.SimpleTarget;
|
import com.bumptech.glide.request.target.SimpleTarget;
|
||||||
|
import com.bumptech.glide.signature.StringSignature;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
@ -119,7 +120,7 @@ public class CoverCache {
|
|||||||
* @param source the cover image.
|
* @param source the cover image.
|
||||||
* @throws IOException exception returned
|
* @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.
|
// Create cache directory if needed.
|
||||||
createCacheDir();
|
createCacheDir();
|
||||||
|
|
||||||
@ -200,11 +201,12 @@ public class CoverCache {
|
|||||||
* @param imageView imageView where picture should be displayed.
|
* @param imageView imageView where picture should be displayed.
|
||||||
* @param file file to load. Must exist!.
|
* @param file file to load. Must exist!.
|
||||||
*/
|
*/
|
||||||
private void loadFromCache(ImageView imageView, File file) {
|
public void loadFromCache(ImageView imageView, File file) {
|
||||||
Glide.with(context)
|
Glide.with(context)
|
||||||
.load(file)
|
.load(file)
|
||||||
.diskCacheStrategy(DiskCacheStrategy.RESULT)
|
.diskCacheStrategy(DiskCacheStrategy.RESULT)
|
||||||
.centerCrop()
|
.centerCrop()
|
||||||
|
.signature(new StringSignature(String.valueOf(file.lastModified())))
|
||||||
.into(imageView);
|
.into(imageView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,6 @@ public interface AppComponent {
|
|||||||
void inject(LibraryUpdateService libraryUpdateService);
|
void inject(LibraryUpdateService libraryUpdateService);
|
||||||
void inject(DownloadService downloadService);
|
void inject(DownloadService downloadService);
|
||||||
void inject(UpdateMangaSyncService updateMangaSyncService);
|
void inject(UpdateMangaSyncService updateMangaSyncService);
|
||||||
|
|
||||||
Application application();
|
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;
|
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.os.Bundle;
|
||||||
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.v4.content.ContextCompat;
|
||||||
import android.support.v4.widget.SwipeRefreshLayout;
|
import android.support.v4.widget.SwipeRefreshLayout;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -10,6 +15,11 @@ import android.widget.ImageView;
|
|||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import com.bumptech.glide.load.model.LazyHeaders;
|
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.Bind;
|
||||||
import butterknife.ButterKnife;
|
import butterknife.ButterKnife;
|
||||||
@ -17,14 +27,16 @@ import eu.kanade.tachiyomi.R;
|
|||||||
import eu.kanade.tachiyomi.data.cache.CoverCache;
|
import eu.kanade.tachiyomi.data.cache.CoverCache;
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
import eu.kanade.tachiyomi.data.database.models.Manga;
|
||||||
import eu.kanade.tachiyomi.data.source.base.Source;
|
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.ui.base.fragment.BaseRxFragment;
|
||||||
|
import eu.kanade.tachiyomi.util.ToastUtil;
|
||||||
import nucleus.factory.RequiresPresenter;
|
import nucleus.factory.RequiresPresenter;
|
||||||
|
|
||||||
@RequiresPresenter(MangaInfoPresenter.class)
|
@RequiresPresenter(MangaInfoPresenter.class)
|
||||||
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
||||||
|
|
||||||
|
private static final int REQUEST_IMAGE_OPEN = 101;
|
||||||
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
|
@Bind(R.id.swipe_refresh) SwipeRefreshLayout swipeRefresh;
|
||||||
|
|
||||||
@Bind(R.id.manga_artist) TextView artist;
|
@Bind(R.id.manga_artist) TextView artist;
|
||||||
@Bind(R.id.manga_author) TextView author;
|
@Bind(R.id.manga_author) TextView author;
|
||||||
@Bind(R.id.manga_chapters) TextView chapterCount;
|
@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_source) TextView source;
|
||||||
@Bind(R.id.manga_summary) TextView description;
|
@Bind(R.id.manga_summary) TextView description;
|
||||||
@Bind(R.id.manga_cover) ImageView cover;
|
@Bind(R.id.manga_cover) ImageView cover;
|
||||||
|
|
||||||
@Bind(R.id.action_favorite) Button favoriteBtn;
|
@Bind(R.id.action_favorite) Button favoriteBtn;
|
||||||
|
@Bind(R.id.fab_edit) FloatingActionButton fabEdit;
|
||||||
|
|
||||||
public static MangaInfoFragment newInstance() {
|
public static MangaInfoFragment newInstance() {
|
||||||
return new MangaInfoFragment();
|
return new MangaInfoFragment();
|
||||||
@ -54,9 +65,20 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
|||||||
View view = inflater.inflate(R.layout.fragment_manga_info, container, false);
|
View view = inflater.inflate(R.layout.fragment_manga_info, container, false);
|
||||||
ButterKnife.bind(this, view);
|
ButterKnife.bind(this, view);
|
||||||
|
|
||||||
favoriteBtn.setOnClickListener(v -> {
|
//Create edit drawable with size 24dp (google guidelines)
|
||||||
getPresenter().toggleFavorite();
|
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);
|
swipeRefresh.setOnRefreshListener(this::fetchMangaFromSource);
|
||||||
|
|
||||||
return view;
|
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) {
|
private void setMangaInfo(Manga manga, Source mangaSource) {
|
||||||
artist.setText(manga.artist);
|
artist.setText(manga.artist);
|
||||||
author.setText(manga.author);
|
author.setText(manga.author);
|
||||||
@ -99,7 +127,7 @@ public class MangaInfoFragment extends BaseRxFragment<MangaInfoPresenter> {
|
|||||||
chapterCount.setText(String.valueOf(count));
|
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);
|
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();
|
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() {
|
public void onFetchMangaDone() {
|
||||||
setRefreshing(false);
|
setRefreshing(false);
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
package eu.kanade.tachiyomi.ui.manga.info;
|
package eu.kanade.tachiyomi.ui.manga.info;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
|
||||||
@ -19,17 +23,42 @@ import rx.schedulers.Schedulers;
|
|||||||
|
|
||||||
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
||||||
|
|
||||||
@Inject DatabaseHelper db;
|
/**
|
||||||
@Inject SourceManager sourceManager;
|
* The id of the restartable.
|
||||||
@Inject CoverCache coverCache;
|
*/
|
||||||
|
|
||||||
protected Source source;
|
|
||||||
private Manga manga;
|
|
||||||
private int count = -1;
|
|
||||||
|
|
||||||
private static final int GET_MANGA = 1;
|
private static final int GET_MANGA = 1;
|
||||||
|
/**
|
||||||
|
* The id of the restartable.
|
||||||
|
*/
|
||||||
private static final int GET_CHAPTER_COUNT = 2;
|
private static final int GET_CHAPTER_COUNT = 2;
|
||||||
|
/**
|
||||||
|
* The id of the restartable.
|
||||||
|
*/
|
||||||
private static final int FETCH_MANGA_INFO = 3;
|
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
|
@Override
|
||||||
protected void onCreate(Bundle savedState) {
|
protected void onCreate(Bundle savedState) {
|
||||||
@ -39,22 +68,29 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
|||||||
onProcessRestart();
|
onProcessRestart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update manga cache
|
||||||
restartableLatestCache(GET_MANGA,
|
restartableLatestCache(GET_MANGA,
|
||||||
() -> Observable.just(manga),
|
() -> Observable.just(manga),
|
||||||
(view, manga) -> view.onNextManga(manga, source));
|
(view, manga) -> view.onNextManga(manga, source));
|
||||||
|
|
||||||
|
// Update chapter count
|
||||||
restartableLatestCache(GET_CHAPTER_COUNT,
|
restartableLatestCache(GET_CHAPTER_COUNT,
|
||||||
() -> Observable.just(count),
|
() -> Observable.just(count),
|
||||||
MangaInfoFragment::setChapterCount);
|
MangaInfoFragment::setChapterCount);
|
||||||
|
|
||||||
|
// Fetch manga info from source
|
||||||
restartableFirst(FETCH_MANGA_INFO,
|
restartableFirst(FETCH_MANGA_INFO,
|
||||||
this::fetchMangaObs,
|
this::fetchMangaObs,
|
||||||
(view, manga) -> view.onFetchMangaDone(),
|
(view, manga) -> view.onFetchMangaDone(),
|
||||||
(view, error) -> view.onFetchMangaError());
|
(view, error) -> view.onFetchMangaError());
|
||||||
|
|
||||||
|
// onEventMainThread receives an event thanks to this line.
|
||||||
registerForStickyEvents();
|
registerForStickyEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when savedState not null
|
||||||
|
*/
|
||||||
private void onProcessRestart() {
|
private void onProcessRestart() {
|
||||||
stop(GET_MANGA);
|
stop(GET_MANGA);
|
||||||
stop(GET_CHAPTER_COUNT);
|
stop(GET_CHAPTER_COUNT);
|
||||||
@ -82,6 +118,9 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fetch manga info from source
|
||||||
|
*/
|
||||||
public void fetchMangaFromSource() {
|
public void fetchMangaFromSource() {
|
||||||
if (isUnsubscribed(FETCH_MANGA_INFO)) {
|
if (isUnsubscribed(FETCH_MANGA_INFO)) {
|
||||||
start(FETCH_MANGA_INFO);
|
start(FETCH_MANGA_INFO);
|
||||||
@ -107,6 +146,16 @@ public class MangaInfoPresenter extends BasePresenter<MangaInfoFragment> {
|
|||||||
refreshManga();
|
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) {
|
private void onMangaFavoriteChange(boolean isFavorite) {
|
||||||
if (isFavorite) {
|
if (isFavorite) {
|
||||||
coverCache.save(manga.thumbnail_url, source.getGlideHeaders());
|
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
|
// Used to refresh the view
|
||||||
private void refreshManga() {
|
protected void refreshManga() {
|
||||||
start(GET_MANGA);
|
start(GET_MANGA);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:layout_width="match_parent"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_height="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:orientation="vertical"
|
android:layout_height="match_parent"
|
||||||
tools:context="eu.kanade.tachiyomi.ui.catalogue.CatalogueFragment">
|
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
|
<!-- 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.support.v4.widget.SwipeRefreshLayout
|
||||||
android:id="@+id/swipe_refresh"
|
android:id="@+id/swipe_refresh"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:orientation="vertical"
|
android:layout_height="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:orientation="vertical">
|
||||||
|
|
||||||
<ScrollView
|
<ScrollView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -50,7 +51,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:scaleType="fitXY"
|
android:scaleType="fitXY"
|
||||||
android:visibility="visible" />
|
android:visibility="visible"/>
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
|
|
||||||
@ -72,7 +73,7 @@
|
|||||||
android:layout_marginTop="5dp"
|
android:layout_marginTop="5dp"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:text="@string/author" />
|
android:text="@string/author"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_author"
|
android:id="@+id/manga_author"
|
||||||
@ -85,7 +86,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:singleLine="true" />
|
android:singleLine="true"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_artist_label"
|
android:id="@+id/manga_artist_label"
|
||||||
@ -97,7 +98,7 @@
|
|||||||
android:layout_below="@id/manga_author_label"
|
android:layout_below="@id/manga_author_label"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:text="@string/artist" />
|
android:text="@string/artist"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_artist"
|
android:id="@+id/manga_artist"
|
||||||
@ -110,7 +111,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:singleLine="true" />
|
android:singleLine="true"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_chapters_label"
|
android:id="@+id/manga_chapters_label"
|
||||||
@ -121,7 +122,7 @@
|
|||||||
android:layout_below="@id/manga_artist_label"
|
android:layout_below="@id/manga_artist_label"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:text="@string/chapters" />
|
android:text="@string/chapters"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_chapters"
|
android:id="@+id/manga_chapters"
|
||||||
@ -134,7 +135,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:singleLine="true" />
|
android:singleLine="true"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_status_label"
|
android:id="@+id/manga_status_label"
|
||||||
@ -146,7 +147,7 @@
|
|||||||
android:layout_below="@id/manga_chapters_label"
|
android:layout_below="@id/manga_chapters_label"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:text="@string/status" />
|
android:text="@string/status"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_status"
|
android:id="@+id/manga_status"
|
||||||
@ -159,7 +160,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:singleLine="true" />
|
android:singleLine="true"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_source_label"
|
android:id="@+id/manga_source_label"
|
||||||
@ -170,7 +171,7 @@
|
|||||||
android:layout_below="@id/manga_status_label"
|
android:layout_below="@id/manga_status_label"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:text="@string/source" />
|
android:text="@string/source"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_source"
|
android:id="@+id/manga_source"
|
||||||
@ -183,7 +184,7 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:maxLines="1"
|
android:maxLines="1"
|
||||||
android:singleLine="true" />
|
android:singleLine="true"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_genres_label"
|
android:id="@+id/manga_genres_label"
|
||||||
@ -194,7 +195,7 @@
|
|||||||
android:layout_below="@id/manga_source_label"
|
android:layout_below="@id/manga_source_label"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:text="@string/genres" />
|
android:text="@string/genres"/>
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_genres"
|
android:id="@+id/manga_genres"
|
||||||
@ -204,7 +205,7 @@
|
|||||||
android:layout_below="@id/manga_genres_label"
|
android:layout_below="@id/manga_genres_label"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:singleLine="false" />
|
android:singleLine="false"/>
|
||||||
|
|
||||||
|
|
||||||
</RelativeLayout>
|
</RelativeLayout>
|
||||||
@ -221,7 +222,7 @@
|
|||||||
android:id="@+id/action_favorite"
|
android:id="@+id/action_favorite"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/add_to_library" />
|
android:text="@string/add_to_library"/>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
@ -238,24 +239,43 @@
|
|||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:singleLine="false"
|
android:singleLine="false"
|
||||||
android:text="@string/description" />
|
android:text="@string/description"/>
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/manga_summary"
|
android:id="@+id/manga_summary"
|
||||||
style="@style/manga_detail_text"
|
style="@style/manga_detail_text"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:focusable="false"
|
android:focusable="false"
|
||||||
android:focusableInTouchMode="false"
|
android:focusableInTouchMode="false"
|
||||||
android:singleLine="false" />
|
android:singleLine="false"/>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
</android.support.v4.widget.SwipeRefreshLayout>
|
</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">@color/colorPrimary</color>
|
||||||
<color name="primary_dark">@color/colorPrimaryDark</color>
|
<color name="primary_dark">@color/colorPrimaryDark</color>
|
||||||
<color name="primary_light">@color/colorPrimaryLight</color>
|
<color name="primary_light">@color/colorPrimaryLight</color>
|
||||||
|
<color name="color_ripple">#E9F1FF</color>
|
||||||
|
|
||||||
<color name="divider">@color/md_light_dividers</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_no_new_chapters">No new chapters found</string>
|
||||||
<string name="notification_new_chapters">New chapters found for:</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_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>
|
</resources>
|
||||||
|
Loading…
Reference in New Issue
Block a user