Add Rapid decoder for better image support. Reorganize readers.

This commit is contained in:
inorichi 2016-01-08 20:16:17 +01:00
parent b735a1f581
commit d03e7e2f8c
28 changed files with 233 additions and 80 deletions

View File

@ -113,6 +113,9 @@ dependencies {
compile 'eu.davidea:flexible-adapter:4.2.0@aar'
compile 'com.nononsenseapps:filepicker:2.5.0'
compile 'com.amulyakhare:com.amulyakhare.textdrawable:1.0.1'
compile 'rapid.decoder:library:0.3.0'
compile 'rapid.decoder:jpeg-decoder:0.3.0'
compile 'rapid.decoder:png-decoder:0.3.0'
compile "com.google.dagger:dagger:$DAGGER_VERSION"
apt "com.google.dagger:dagger-compiler:$DAGGER_VERSION"

View File

@ -84,11 +84,8 @@ public class PreferencesHelper {
return rxPrefs.getFloat(getKey(R.string.pref_custom_brightness_value_key), 0F);
}
public int getReaderTheme() {
return prefs.getInt(getKey(R.string.pref_reader_theme_key), 0);
}
public int getDefaultViewer() {
// TODO use IntListPreference
return Integer.parseInt(prefs.getString(getKey(R.string.pref_default_viewer_key), "1"));
}
@ -100,6 +97,14 @@ public class PreferencesHelper {
return rxPrefs.getInteger(getKey(R.string.pref_library_columns_landscape_key), 0);
}
public Preference<Integer> imageDecoder() {
return rxPrefs.getInteger(getKey(R.string.pref_image_decoder_key), 0);
}
public Preference<Integer> readerTheme() {
return rxPrefs.getInteger(getKey(R.string.pref_reader_theme_key), 0);
}
public String getSourceUsername(Source source) {
return prefs.getString(SOURCE_ACCOUNT_USERNAME + source.getId(), "");
}

View File

@ -30,9 +30,9 @@ import eu.kanade.mangafeed.data.preference.PreferencesHelper;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.ui.base.activity.BaseRxActivity;
import eu.kanade.mangafeed.ui.reader.viewer.base.BaseReader;
import eu.kanade.mangafeed.ui.reader.viewer.horizontal.LeftToRightReader;
import eu.kanade.mangafeed.ui.reader.viewer.horizontal.RightToLeftReader;
import eu.kanade.mangafeed.ui.reader.viewer.vertical.VerticalReader;
import eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal.LeftToRightReader;
import eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal.RightToLeftReader;
import eu.kanade.mangafeed.ui.reader.viewer.pager.vertical.VerticalReader;
import eu.kanade.mangafeed.ui.reader.viewer.webtoon.WebtoonReader;
import eu.kanade.mangafeed.util.GLUtil;
import eu.kanade.mangafeed.util.ToastUtil;
@ -85,9 +85,6 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
if (savedState != null && readerMenu.showing)
readerMenu.show(false);
readerTheme = preferences.getReaderTheme();
applyTheme();
initializeSettings();
maxBitmapSize = GLUtil.getMaxTextureSize();
@ -211,6 +208,11 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
subscriptions.add(preferences.customBrightness()
.asObservable()
.subscribe(this::setCustomBrightness));
subscriptions.add(preferences.readerTheme()
.asObservable()
.distinctUntilChanged()
.subscribe(this::applyTheme));
}
private void setOrientation(boolean locked) {
@ -291,14 +293,17 @@ public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
recreate();
}
private void applyTheme() {
private void applyTheme(int theme) {
readerTheme = theme;
View rootView = getWindow().getDecorView().getRootView();
if (readerTheme == BLACK_THEME) {
if (theme == BLACK_THEME) {
rootView.setBackgroundColor(Color.BLACK);
pageNumber.setTextColor(ContextCompat.getColor(this, R.color.light_grey));
pageNumber.setBackgroundColor(ContextCompat.getColor(this, R.color.page_number_background_black));
} else {
rootView.setBackgroundColor(Color.WHITE);
pageNumber.setTextColor(ContextCompat.getColor(this, R.color.primary_text));
pageNumber.setBackgroundColor(ContextCompat.getColor(this, R.color.page_number_background));
}
}

View File

@ -2,7 +2,6 @@ package eu.kanade.mangafeed.ui.reader;
import android.app.Dialog;
import android.content.Context;
import android.support.v7.app.AlertDialog;
import android.support.v7.widget.Toolbar;
import android.view.Gravity;
import android.view.Menu;
@ -20,6 +19,8 @@ import android.widget.RelativeLayout;
import android.widget.SeekBar;
import android.widget.TextView;
import com.afollestad.materialdialogs.MaterialDialog;
import java.text.DecimalFormat;
import butterknife.Bind;
@ -191,15 +192,14 @@ public class ReaderMenu {
// Reader selector
readerSelector.setOnClickListener(v -> {
final Manga manga = activity.getPresenter().getManga();
final Dialog dialog = new AlertDialog.Builder(activity)
.setSingleChoiceItems(R.array.viewers_selector, manga.viewer, (d, which) -> {
if (manga.viewer != which) {
activity.setMangaDefaultViewer(which);
}
d.dismiss();
})
.create();
showImmersiveDialog(dialog);
showImmersiveDialog(new MaterialDialog.Builder(activity)
.items(R.array.viewers_selector)
.itemsCallbackSingleChoice(manga.viewer,
(d, itemView, which, text) -> {
activity.setMangaDefaultViewer(which);
return true;
})
.build());
});
// Extra settings menu
@ -245,6 +245,8 @@ public class ReaderMenu {
@Bind(R.id.show_page_number) CheckBox showPageNumber;
@Bind(R.id.hide_status_bar) CheckBox hideStatusBar;
@Bind(R.id.keep_screen_on) CheckBox keepScreenOn;
@Bind(R.id.image_decoder) TextView imageDecoder;
@Bind(R.id.reader_theme) TextView readerTheme;
public SettingsPopupWindow(View view) {
super(view, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
@ -272,6 +274,30 @@ public class ReaderMenu {
keepScreenOn.setOnCheckedChangeListener((view, isChecked) ->
preferences.keepScreenOn().set(isChecked));
imageDecoder.setOnClickListener(v -> {
showImmersiveDialog(new MaterialDialog.Builder(activity)
.title(R.string.pref_image_decoder)
.items(R.array.image_decoders)
.itemsCallbackSingleChoice(preferences.imageDecoder().get(),
(dialog, itemView, which, text) -> {
preferences.imageDecoder().set(which);
return true;
})
.build());
});
readerTheme.setOnClickListener(v -> {
showImmersiveDialog(new MaterialDialog.Builder(activity)
.title(R.string.pref_reader_theme)
.items(R.array.reader_themes)
.itemsCallbackSingleChoice(preferences.readerTheme().get(),
(dialog, itemView, which, text) -> {
preferences.readerTheme().set(which);
return true;
})
.build());
});
}
}

View File

@ -0,0 +1,53 @@
package eu.kanade.mangafeed.ui.reader.decoder;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
import android.graphics.Rect;
import android.net.Uri;
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
import rapid.decoder.BitmapDecoder;
/**
* A very simple implementation of {@link com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder}
* using the RapidDecoder library (https://github.com/suckgamony/RapidDecoder). For PNGs, this can
* give more reliable decoding and better performance. For JPGs, it is slower and can run out of
* memory with large images, but has better support for grayscale and CMYK images.
*
* This is an incomplete and untested implementation provided as an example only.
*/
public class RapidImageRegionDecoder implements ImageRegionDecoder {
private BitmapDecoder decoder;
@Override
public Point init(Context context, Uri uri) throws Exception {
decoder = BitmapDecoder.from(context, uri);
decoder.useBuiltInDecoder(true);
return new Point(decoder.sourceWidth(), decoder.sourceHeight());
}
@Override
public synchronized Bitmap decodeRegion(Rect sRect, int sampleSize) {
try {
return decoder.reset().region(sRect).scale(sRect.width()/sampleSize, sRect.height()/sampleSize).decode();
} catch (Exception e) {
return null;
}
}
@Override
public boolean isReady() {
return decoder != null;
}
@Override
public void recycle() {
BitmapDecoder.destroyMemoryCache();
BitmapDecoder.destroyDiskCache();
decoder.reset();
decoder = null;
}
}

View File

@ -2,16 +2,24 @@ package eu.kanade.mangafeed.ui.reader.viewer.base;
import android.view.MotionEvent;
import com.davemorrissey.labs.subscaleview.decoder.ImageRegionDecoder;
import com.davemorrissey.labs.subscaleview.decoder.SkiaImageRegionDecoder;
import java.util.List;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.ui.base.fragment.BaseFragment;
import eu.kanade.mangafeed.ui.reader.ReaderActivity;
import eu.kanade.mangafeed.ui.reader.decoder.RapidImageRegionDecoder;
public abstract class BaseReader extends BaseFragment {
protected int currentPage;
protected List<Page> pages;
protected Class<? extends ImageRegionDecoder> regionDecoderClass;
public static final int RAPID_DECODER = 0;
public static final int SKIA_DECODER = 1;
public void updatePageNumber() {
getReaderActivity().onPageChanged(getCurrentPage(), getTotalPages());
@ -42,6 +50,22 @@ public abstract class BaseReader extends BaseFragment {
public abstract void onPageListReady(List<Page> pages, int currentPage);
public abstract boolean onImageTouch(MotionEvent motionEvent);
public void setRegionDecoderClass(int value) {
switch (value) {
case RAPID_DECODER:
default:
regionDecoderClass = RapidImageRegionDecoder.class;
break;
case SKIA_DECODER:
regionDecoderClass = SkiaImageRegionDecoder.class;
break;
}
}
public Class<? extends ImageRegionDecoder> getRegionDecoderClass() {
return regionDecoderClass;
}
public ReaderActivity getReaderActivity() {
return (ReaderActivity) getActivity();
}

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.base;
public interface OnChapterBoundariesOutListener {
void onFirstPageOutEvent();

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.base;
public interface OnChapterSingleTapListener {
void onCenterTap();

View File

@ -1,9 +1,11 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.pager;
import android.support.v4.view.PagerAdapter;
import android.view.MotionEvent;
import android.view.ViewGroup;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterBoundariesOutListener;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterSingleTapListener;
import rx.functions.Action1;
public interface Pager {

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.pager;
import android.view.GestureDetector;
import android.view.MotionEvent;

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.pager;
import android.view.MotionEvent;
import android.view.ViewGroup;
@ -8,7 +8,9 @@ import java.util.List;
import eu.kanade.mangafeed.R;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.ui.reader.viewer.base.BaseReader;
import rx.Subscription;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterBoundariesOutListener;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterSingleTapListener;
import rx.subscriptions.CompositeSubscription;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@ -18,7 +20,7 @@ public abstract class PagerReader extends BaseReader {
protected Pager pager;
protected boolean transitions;
protected Subscription transitionsSubscription;
protected CompositeSubscription subscriptions;
protected void initializePager(Pager pager) {
this.pager = pager;
@ -55,16 +57,25 @@ public abstract class PagerReader extends BaseReader {
adapter = new PagerReaderAdapter(getChildFragmentManager());
pager.setAdapter(adapter);
setPages();
transitionsSubscription = getReaderActivity().getPreferences().enableTransitions()
subscriptions = new CompositeSubscription();
subscriptions.add(getReaderActivity().getPreferences().imageDecoder()
.asObservable()
.subscribe(value -> transitions = value);
.doOnNext(this::setRegionDecoderClass)
.skip(1)
.distinctUntilChanged()
.subscribe(v -> adapter.notifyDataSetChanged()));
subscriptions.add(getReaderActivity().getPreferences().enableTransitions()
.asObservable()
.subscribe(value -> transitions = value));
setPages();
}
@Override
public void onDestroyView() {
transitionsSubscription.unsubscribe();
subscriptions.unsubscribe();
super.onDestroyView();
}

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.pager;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentManager;

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.common;
package eu.kanade.mangafeed.ui.reader.viewer.pager;
import android.os.Bundle;
import android.support.annotation.Nullable;
@ -54,6 +54,7 @@ public class PagerReaderFragment extends BaseFragment {
View view = inflater.inflate(R.layout.item_pager_reader, container, false);
ButterKnife.bind(this, view);
ReaderActivity activity = (ReaderActivity) getActivity();
BaseReader parentFragment = (BaseReader) getParentFragment();
if (activity.getReaderTheme() == ReaderActivity.BLACK_THEME) {
progressText.setTextColor(ContextCompat.getColor(getContext(), R.color.light_grey));
@ -64,8 +65,8 @@ public class PagerReaderFragment extends BaseFragment {
imageView.setDoubleTapZoomStyle(SubsamplingScaleImageView.ZOOM_FOCUS_FIXED);
imageView.setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_INSIDE);
imageView.setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_INSIDE);
imageView.setOnTouchListener((v, motionEvent) ->
((BaseReader) getParentFragment()).onImageTouch(motionEvent));
imageView.setRegionDecoderClass(parentFragment.getRegionDecoderClass());
imageView.setOnTouchListener((v, motionEvent) -> parentFragment.onImageTouch(motionEvent));
retryButton.setOnTouchListener((v, event) -> {
if (event.getAction() == MotionEvent.ACTION_UP) {
@ -76,25 +77,16 @@ public class PagerReaderFragment extends BaseFragment {
return true;
});
observeStatus();
return view;
}
@Override
public void onDestroyView() {
ButterKnife.unbind(this);
super.onDestroyView();
}
public void onStart() {
super.onStart();
observeStatus();
}
@Override
public void onStop() {
unsubscribeProgress();
unsubscribeStatus();
super.onStop();
ButterKnife.unbind(this);
super.onDestroyView();
}
public void setPage(Page page) {

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.horizontal;
package eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal;
import android.content.Context;
import android.support.v4.view.ViewPager;
@ -6,10 +6,10 @@ import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import eu.kanade.mangafeed.ui.reader.viewer.common.OnChapterBoundariesOutListener;
import eu.kanade.mangafeed.ui.reader.viewer.common.OnChapterSingleTapListener;
import eu.kanade.mangafeed.ui.reader.viewer.common.PagerGestureListener;
import eu.kanade.mangafeed.ui.reader.viewer.common.Pager;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterBoundariesOutListener;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterSingleTapListener;
import eu.kanade.mangafeed.ui.reader.viewer.pager.PagerGestureListener;
import eu.kanade.mangafeed.ui.reader.viewer.pager.Pager;
import rx.functions.Action1;
public class HorizontalPager extends ViewPager implements Pager {

View File

@ -1,11 +1,11 @@
package eu.kanade.mangafeed.ui.reader.viewer.horizontal;
package eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import eu.kanade.mangafeed.ui.reader.viewer.common.PagerReader;
import eu.kanade.mangafeed.ui.reader.viewer.pager.PagerReader;
public abstract class HorizontalReader extends PagerReader {

View File

@ -1,4 +1,4 @@
package eu.kanade.mangafeed.ui.reader.viewer.horizontal;
package eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal;
public class LeftToRightReader extends HorizontalReader {

View File

@ -1,10 +1,11 @@
package eu.kanade.mangafeed.ui.reader.viewer.horizontal;
package eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import eu.kanade.mangafeed.data.source.model.Page;
import eu.kanade.mangafeed.ui.reader.viewer.pager.horizontal.HorizontalReader;
public class RightToLeftReader extends HorizontalReader {

View File

@ -1,14 +1,14 @@
package eu.kanade.mangafeed.ui.reader.viewer.vertical;
package eu.kanade.mangafeed.ui.reader.viewer.pager.vertical;
import android.content.Context;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.MotionEvent;
import eu.kanade.mangafeed.ui.reader.viewer.common.OnChapterBoundariesOutListener;
import eu.kanade.mangafeed.ui.reader.viewer.common.OnChapterSingleTapListener;
import eu.kanade.mangafeed.ui.reader.viewer.common.PagerGestureListener;
import eu.kanade.mangafeed.ui.reader.viewer.common.Pager;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterBoundariesOutListener;
import eu.kanade.mangafeed.ui.reader.viewer.base.OnChapterSingleTapListener;
import eu.kanade.mangafeed.ui.reader.viewer.pager.PagerGestureListener;
import eu.kanade.mangafeed.ui.reader.viewer.pager.Pager;
import rx.functions.Action1;
public class VerticalPager extends VerticalViewPagerImpl implements Pager {

View File

@ -1,11 +1,12 @@
package eu.kanade.mangafeed.ui.reader.viewer.vertical;
package eu.kanade.mangafeed.ui.reader.viewer.pager.vertical;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import eu.kanade.mangafeed.ui.reader.viewer.common.PagerReader;
import eu.kanade.mangafeed.ui.reader.viewer.pager.PagerReader;
import eu.kanade.mangafeed.ui.reader.viewer.pager.vertical.VerticalPager;
public class VerticalReader extends PagerReader {

View File

@ -14,7 +14,7 @@
* limitations under the License.
*/
package eu.kanade.mangafeed.ui.reader.viewer.vertical;
package eu.kanade.mangafeed.ui.reader.viewer.pager.vertical;
import android.content.Context;
import android.content.res.Resources;

View File

@ -12,7 +12,7 @@
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
style="@style/grey_text"
style="@style/reader_menu_settings_item"
android:text="@string/pref_custom_brightness"
android:id="@+id/custom_brightness" />

View File

@ -8,32 +8,36 @@
android:paddingTop="5dp"
android:paddingBottom="5dp">
<TextView
android:id="@+id/reader_theme"
android:paddingLeft="32dp"
style="@style/reader_menu_settings_item"
android:text="@string/pref_reader_theme"/>
<TextView
android:id="@+id/image_decoder"
android:paddingLeft="32dp"
style="@style/reader_menu_settings_item"
android:text="@string/pref_image_decoder"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/enable_transitions"
style="@style/grey_text"
style="@style/reader_menu_settings_item"
android:text="@string/pref_enable_transitions"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/show_page_number"
style="@style/grey_text"
style="@style/reader_menu_settings_item"
android:text="@string/pref_show_page_number"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/hide_status_bar"
style="@style/grey_text"
style="@style/reader_menu_settings_item"
android:text="@string/pref_hide_status_bar"/>
<CheckBox
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/keep_screen_on"
style="@style/grey_text"
style="@style/reader_menu_settings_item"
android:text="@string/pref_keep_screen_on"/>
</LinearLayout>

View File

@ -38,4 +38,14 @@
<item>1</item>
</string-array>
<string-array name="image_decoders">
<item>@string/rapid_decoder</item>
<item>@string/skia_decoder</item>
</string-array>
<string-array name="image_decoders_values">
<item>0</item>
<item>1</item>
</string-array>
</resources>

View File

@ -20,6 +20,7 @@
<string name="pref_custom_brightness_key">pref_custom_brightness_key</string>
<string name="pref_custom_brightness_value_key">pref_custom_brightness_value_key</string>
<string name="pref_reader_theme_key">pref_reader_theme_key</string>
<string name="pref_image_decoder_key">pref_image_decoder_key</string>
<string name="pref_download_directory_key">pref_download_directory_key</string>
<string name="pref_download_slots_key">pref_download_slots_key</string>

View File

@ -80,6 +80,9 @@
<string name="right_to_left_viewer">Right to left</string>
<string name="vertical_viewer">Vertical</string>
<string name="webtoon_viewer">Webtoon (experimental)</string>
<string name="pref_image_decoder">Image decoder</string>
<string name="rapid_decoder">Rapid</string>
<string name="skia_decoder">Skia</string>
<!-- Downloads section -->
<string name="pref_download_directory">Downloads directory</string>

View File

@ -109,7 +109,10 @@
<item name="android:windowExitAnimation">@anim/exit_to_left</item>
</style>
<style name="grey_text">
<style name="reader_menu_settings_item">
<item name="android:textColor">@color/md_grey_300</item>
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">36dp</item>
<item name="android:gravity">center</item>
</style>
</resources>

View File

@ -36,4 +36,12 @@
android:defaultValue="0"
android:summary="%s"/>
<eu.kanade.mangafeed.ui.setting.preference.IntListPreference
android:title="@string/pref_image_decoder"
android:key="@string/pref_image_decoder_key"
android:entries="@array/image_decoders"
android:entryValues="@array/image_decoders_values"
android:defaultValue="0"
android:summary="%s" />
</PreferenceScreen>

View File

@ -23,5 +23,6 @@ allprojects {
maven { url "http://dl.bintray.com/davideas/maven" }
maven { url "https://jitpack.io" }
maven { url 'http://dl.bintray.com/amulyakhare/maven' }
maven { url 'https://github.com/suckgamony/RapidDecoder/raw/master/repository' }
}
}