Reader view in Kotlin. Upgrade gradle wrapper. Remove ButterKnife from the project
This commit is contained in:
parent
396a79899e
commit
4ccce424de
14 changed files with 676 additions and 854 deletions
|
@ -136,7 +136,6 @@ dependencies {
|
|||
compile "com.pushtorefresh.storio:sqlite-annotations:$STORIO_VERSION"
|
||||
compile 'info.android15.nucleus:nucleus:2.0.5'
|
||||
compile 'com.github.bumptech.glide:glide:3.7.0'
|
||||
compile 'com.jakewharton:butterknife:7.0.1'
|
||||
compile 'com.jakewharton.timber:timber:4.1.1'
|
||||
compile 'ch.acra:acra:4.8.3'
|
||||
compile "frankiesardo:icepick:$ICEPICK_VERSION"
|
||||
|
|
|
@ -31,7 +31,8 @@
|
|||
</activity>
|
||||
<activity
|
||||
android:name=".ui.reader.ReaderActivity"
|
||||
android:parentActivityName=".ui.manga.MangaActivity">
|
||||
android:parentActivityName=".ui.manga.MangaActivity"
|
||||
android:theme="@style/Theme.Reader">
|
||||
<meta-data
|
||||
android:name="android.support.PARENT_ACTIVITY"
|
||||
android:value=".ui.manga.MangaActivity" />
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package eu.kanade.tachiyomi.ui.base.listener
|
||||
|
||||
import android.view.animation.Animation
|
||||
|
||||
open class SimpleAnimationListener : Animation.AnimationListener {
|
||||
override fun onAnimationRepeat(animation: Animation) {}
|
||||
|
||||
override fun onAnimationEnd(animation: Animation) {}
|
||||
|
||||
override fun onAnimationStart(animation: Animation) {}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
package eu.kanade.tachiyomi.ui.base.listener
|
||||
|
||||
import android.widget.SeekBar
|
||||
|
||||
open class SimpleSeekBarListener : SeekBar.OnSeekBarChangeListener {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {}
|
||||
|
||||
override fun onStartTrackingTouch(seekBar: SeekBar) {}
|
||||
|
||||
override fun onStopTrackingTouch(seekBar: SeekBar) {}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package eu.kanade.tachiyomi.widget
|
||||
package eu.kanade.tachiyomi.ui.base.listener
|
||||
|
||||
import android.text.Editable
|
||||
import android.text.TextWatcher
|
|
@ -7,7 +7,7 @@ import android.view.View
|
|||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.database.models.MangaSync
|
||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||
import eu.kanade.tachiyomi.ui.base.listener.SimpleTextWatcher
|
||||
import kotlinx.android.synthetic.main.dialog_myanimelist_search.view.*
|
||||
import rx.Subscription
|
||||
import rx.android.schedulers.AndroidSchedulers
|
||||
|
|
|
@ -1,423 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.reader;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import eu.kanade.tachiyomi.R;
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
|
||||
import eu.kanade.tachiyomi.data.source.model.Page;
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity;
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader;
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.LeftToRightReader;
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader;
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical.VerticalReader;
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonReader;
|
||||
import eu.kanade.tachiyomi.util.GLUtil;
|
||||
import eu.kanade.tachiyomi.util.ToastUtil;
|
||||
import icepick.Icepick;
|
||||
import nucleus.factory.RequiresPresenter;
|
||||
import rx.Subscription;
|
||||
import rx.subscriptions.CompositeSubscription;
|
||||
|
||||
@RequiresPresenter(ReaderPresenter.class)
|
||||
public class ReaderActivity extends BaseRxActivity<ReaderPresenter> {
|
||||
|
||||
@Bind(R.id.page_number) TextView pageNumber;
|
||||
@Bind(R.id.toolbar) Toolbar toolbar;
|
||||
|
||||
private BaseReader viewer;
|
||||
private ReaderMenu readerMenu;
|
||||
|
||||
private int uiFlags;
|
||||
private int readerTheme;
|
||||
protected CompositeSubscription subscriptions;
|
||||
private Subscription customBrightnessSubscription;
|
||||
|
||||
private int maxBitmapSize;
|
||||
|
||||
public static final int LEFT_TO_RIGHT = 1;
|
||||
public static final int RIGHT_TO_LEFT = 2;
|
||||
public static final int VERTICAL = 3;
|
||||
public static final int WEBTOON = 4;
|
||||
|
||||
public static final int BLACK_THEME = 1;
|
||||
|
||||
public static Intent newIntent(Context context) {
|
||||
return new Intent(context, ReaderActivity.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedState) {
|
||||
setTheme(R.style.Theme_Reader);
|
||||
super.onCreate(savedState);
|
||||
setContentView(R.layout.activity_reader);
|
||||
ButterKnife.bind(this);
|
||||
|
||||
setupToolbar(toolbar);
|
||||
subscriptions = new CompositeSubscription();
|
||||
|
||||
readerMenu = new ReaderMenu(this);
|
||||
Icepick.restoreInstanceState(readerMenu, savedState);
|
||||
if (savedState != null && readerMenu.showing)
|
||||
readerMenu.show(false);
|
||||
|
||||
initializeSettings();
|
||||
|
||||
|
||||
maxBitmapSize = GLUtil.getMaxTextureSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
setSystemUiVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
if (viewer != null)
|
||||
getPresenter().setCurrentPage(viewer.getActivePage());
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
subscriptions.unsubscribe();
|
||||
readerMenu.destroy();
|
||||
viewer = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return readerMenu.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return readerMenu.onOptionsItemSelected(item) || super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(@NonNull Bundle outState) {
|
||||
Icepick.saveInstanceState(readerMenu, outState);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
if (viewer != null)
|
||||
getPresenter().setCurrentPage(viewer.getActivePage());
|
||||
getPresenter().onChapterLeft();
|
||||
|
||||
int chapterToUpdate = getPresenter().getMangaSyncChapterToUpdate();
|
||||
|
||||
if (chapterToUpdate > 0) {
|
||||
if (getPresenter().prefs.askUpdateMangaSync()) {
|
||||
new MaterialDialog.Builder(this)
|
||||
.content(getString(R.string.confirm_update_manga_sync, chapterToUpdate))
|
||||
.positiveText(R.string.button_yes)
|
||||
.negativeText(R.string.button_no)
|
||||
.onPositive((dialog, which) -> {
|
||||
getPresenter().updateMangaSyncLastChapterRead();
|
||||
})
|
||||
.onAny((dialog1, which1) -> {
|
||||
finish();
|
||||
})
|
||||
.show();
|
||||
} else {
|
||||
getPresenter().updateMangaSyncLastChapterRead();
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
if (hasFocus) {
|
||||
setSystemUiVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
int action = event.getAction();
|
||||
int keyCode = event.getKeyCode();
|
||||
switch (keyCode) {
|
||||
case KeyEvent.KEYCODE_VOLUME_DOWN:
|
||||
if (action == KeyEvent.ACTION_UP && viewer != null)
|
||||
viewer.moveToNext();
|
||||
return true;
|
||||
case KeyEvent.KEYCODE_VOLUME_UP:
|
||||
if (action == KeyEvent.ACTION_UP && viewer != null)
|
||||
viewer.moveToPrevious();
|
||||
return true;
|
||||
default:
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
public void onChapterError() {
|
||||
finish();
|
||||
ToastUtil.showShort(this, R.string.page_list_error);
|
||||
}
|
||||
|
||||
public void onChapterAppendError() {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
public void onChapterReady(Manga manga, Chapter chapter, Page currentPage) {
|
||||
List<Page> pages = chapter.getPages();
|
||||
if (currentPage == null) {
|
||||
currentPage = pages.get(pages.size() - 1);
|
||||
}
|
||||
|
||||
if (viewer == null) {
|
||||
viewer = getOrCreateViewer(manga);
|
||||
}
|
||||
viewer.onPageListReady(chapter, currentPage);
|
||||
readerMenu.setActiveManga(manga);
|
||||
readerMenu.setActiveChapter(chapter, currentPage.getPageNumber());
|
||||
}
|
||||
|
||||
public void onEnterChapter(Chapter chapter, int currentPage) {
|
||||
if (currentPage == -1) {
|
||||
currentPage = chapter.getPages().size() - 1;
|
||||
}
|
||||
getPresenter().setActiveChapter(chapter);
|
||||
readerMenu.setActiveChapter(chapter, currentPage);
|
||||
}
|
||||
|
||||
public void onAppendChapter(Chapter chapter) {
|
||||
viewer.onPageListAppendReady(chapter);
|
||||
}
|
||||
|
||||
public void onAdjacentChapters(Chapter previous, Chapter next) {
|
||||
readerMenu.onAdjacentChapters(previous, next);
|
||||
}
|
||||
|
||||
private BaseReader getOrCreateViewer(Manga manga) {
|
||||
int mangaViewer = manga.viewer == 0 ? getPreferences().getDefaultViewer() : manga.viewer;
|
||||
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
|
||||
// Try to reuse the viewer using its tag
|
||||
BaseReader fragment = (BaseReader) fm.findFragmentByTag(manga.viewer + "");
|
||||
if (fragment == null) {
|
||||
// Create a new viewer
|
||||
switch (mangaViewer) {
|
||||
case LEFT_TO_RIGHT: default:
|
||||
fragment = new LeftToRightReader();
|
||||
break;
|
||||
case RIGHT_TO_LEFT:
|
||||
fragment = new RightToLeftReader();
|
||||
break;
|
||||
case VERTICAL:
|
||||
fragment = new VerticalReader();
|
||||
break;
|
||||
case WEBTOON:
|
||||
fragment = new WebtoonReader();
|
||||
break;
|
||||
}
|
||||
|
||||
fm.beginTransaction().replace(R.id.reader, fragment, manga.viewer + "").commit();
|
||||
}
|
||||
return fragment;
|
||||
}
|
||||
|
||||
public void onPageChanged(int currentPageIndex, int totalPages) {
|
||||
String page = (currentPageIndex + 1) + "/" + totalPages;
|
||||
pageNumber.setText(page);
|
||||
readerMenu.onPageChanged(currentPageIndex);
|
||||
}
|
||||
|
||||
public void gotoPageInCurrentChapter(int pageIndex) {
|
||||
Page requestedPage = viewer.getActivePage().getChapter().getPages().get(pageIndex);
|
||||
viewer.setActivePage(requestedPage);
|
||||
}
|
||||
|
||||
public void onCenterSingleTap() {
|
||||
readerMenu.toggle();
|
||||
}
|
||||
|
||||
public void requestNextChapter() {
|
||||
getPresenter().setCurrentPage(viewer.getActivePage());
|
||||
if (!getPresenter().loadNextChapter()) {
|
||||
ToastUtil.showShort(this, R.string.no_next_chapter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void requestPreviousChapter() {
|
||||
getPresenter().setCurrentPage(viewer.getActivePage());
|
||||
if (!getPresenter().loadPreviousChapter()) {
|
||||
ToastUtil.showShort(this, R.string.no_previous_chapter);
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeSettings() {
|
||||
PreferencesHelper preferences = getPreferences();
|
||||
|
||||
subscriptions.add(preferences.showPageNumber()
|
||||
.asObservable()
|
||||
.subscribe(this::setPageNumberVisibility));
|
||||
|
||||
subscriptions.add(preferences.rotation()
|
||||
.asObservable()
|
||||
.subscribe(this::setRotation));
|
||||
|
||||
subscriptions.add(preferences.hideStatusBar()
|
||||
.asObservable()
|
||||
.subscribe(this::setStatusBarVisibility));
|
||||
|
||||
subscriptions.add(preferences.keepScreenOn()
|
||||
.asObservable()
|
||||
.subscribe(this::setKeepScreenOn));
|
||||
|
||||
subscriptions.add(preferences.customBrightness()
|
||||
.asObservable()
|
||||
.subscribe(this::setCustomBrightness));
|
||||
|
||||
subscriptions.add(preferences.readerTheme()
|
||||
.asObservable()
|
||||
.distinctUntilChanged()
|
||||
.subscribe(this::applyTheme));
|
||||
}
|
||||
|
||||
private void setRotation(int rotation) {
|
||||
switch (rotation) {
|
||||
// Rotation free
|
||||
case 1:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
|
||||
break;
|
||||
// Lock in current rotation
|
||||
case 2:
|
||||
int currentOrientation = getResources().getConfiguration().orientation;
|
||||
setRotation(currentOrientation == Configuration.ORIENTATION_PORTRAIT ? 3 : 4);
|
||||
break;
|
||||
// Lock in portrait
|
||||
case 3:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
|
||||
break;
|
||||
// Lock in landscape
|
||||
case 4:
|
||||
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void setPageNumberVisibility(boolean visible) {
|
||||
pageNumber.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
|
||||
}
|
||||
|
||||
private void setKeepScreenOn(boolean enabled) {
|
||||
if (enabled) {
|
||||
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
} else {
|
||||
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCustomBrightness(boolean enabled) {
|
||||
if (enabled) {
|
||||
subscriptions.add(customBrightnessSubscription = getPreferences().customBrightnessValue()
|
||||
.asObservable()
|
||||
.subscribe(this::setCustomBrightnessValue));
|
||||
} else {
|
||||
if (customBrightnessSubscription != null)
|
||||
subscriptions.remove(customBrightnessSubscription);
|
||||
setCustomBrightnessValue(-1);
|
||||
}
|
||||
}
|
||||
|
||||
private void setCustomBrightnessValue(float value) {
|
||||
WindowManager.LayoutParams layout = getWindow().getAttributes();
|
||||
layout.screenBrightness = value;
|
||||
getWindow().setAttributes(layout);
|
||||
}
|
||||
|
||||
private void setStatusBarVisibility(boolean hidden) {
|
||||
createUiHideFlags(hidden);
|
||||
setSystemUiVisibility();
|
||||
}
|
||||
|
||||
private void createUiHideFlags(boolean statusBarHidden) {
|
||||
uiFlags = 0;
|
||||
uiFlags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
|
||||
if (statusBarHidden) {
|
||||
uiFlags |= View.SYSTEM_UI_FLAG_LAYOUT_STABLE
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
|
||||
| View.SYSTEM_UI_FLAG_FULLSCREEN;
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
uiFlags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
|
||||
}
|
||||
}
|
||||
|
||||
public void setSystemUiVisibility() {
|
||||
getWindow().getDecorView().setSystemUiVisibility(uiFlags);
|
||||
}
|
||||
|
||||
protected void setMangaDefaultViewer(int viewer) {
|
||||
getPresenter().updateMangaViewer(viewer);
|
||||
recreate();
|
||||
}
|
||||
|
||||
private void applyTheme(int theme) {
|
||||
readerTheme = theme;
|
||||
View rootView = getWindow().getDecorView().getRootView();
|
||||
if (theme == BLACK_THEME) {
|
||||
rootView.setBackgroundColor(Color.BLACK);
|
||||
pageNumber.setTextColor(ContextCompat.getColor(this, R.color.textColorPrimaryDark));
|
||||
pageNumber.setBackgroundColor(ContextCompat.getColor(this, R.color.backgroundDark));
|
||||
} else {
|
||||
rootView.setBackgroundColor(Color.WHITE);
|
||||
pageNumber.setTextColor(ContextCompat.getColor(this, R.color.textColorPrimaryLight));
|
||||
pageNumber.setBackgroundColor(ContextCompat.getColor(this, R.color.backgroundLight));
|
||||
}
|
||||
}
|
||||
|
||||
public int getReaderTheme() {
|
||||
return readerTheme;
|
||||
}
|
||||
|
||||
public PreferencesHelper getPreferences() {
|
||||
return getPresenter().prefs;
|
||||
}
|
||||
|
||||
public BaseReader getViewer() {
|
||||
return viewer;
|
||||
}
|
||||
|
||||
public int getMaxBitmapSize() {
|
||||
return maxBitmapSize;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,536 @@
|
|||
package eu.kanade.tachiyomi.ui.reader
|
||||
|
||||
import android.app.Dialog
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.ActivityInfo
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Color
|
||||
import android.os.Build
|
||||
import android.os.Bundle
|
||||
import android.support.v4.content.ContextCompat
|
||||
import android.view.*
|
||||
import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
import android.view.animation.Animation
|
||||
import android.view.animation.AnimationUtils
|
||||
import android.widget.SeekBar
|
||||
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
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.data.source.model.Page
|
||||
import eu.kanade.tachiyomi.ui.base.activity.BaseRxActivity
|
||||
import eu.kanade.tachiyomi.ui.base.listener.SimpleAnimationListener
|
||||
import eu.kanade.tachiyomi.ui.base.listener.SimpleSeekBarListener
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.base.BaseReader
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.LeftToRightReader
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.horizontal.RightToLeftReader
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.vertical.VerticalReader
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonReader
|
||||
import eu.kanade.tachiyomi.util.GLUtil
|
||||
import eu.kanade.tachiyomi.util.toast
|
||||
import kotlinx.android.synthetic.main.activity_reader.*
|
||||
import kotlinx.android.synthetic.main.reader_menu.*
|
||||
import nucleus.factory.RequiresPresenter
|
||||
import rx.Subscription
|
||||
import rx.subscriptions.CompositeSubscription
|
||||
import java.text.DecimalFormat
|
||||
|
||||
@RequiresPresenter(ReaderPresenter::class)
|
||||
class ReaderActivity : BaseRxActivity<ReaderPresenter>() {
|
||||
|
||||
companion object {
|
||||
@Suppress("unused")
|
||||
const val LEFT_TO_RIGHT = 1
|
||||
const val RIGHT_TO_LEFT = 2
|
||||
const val VERTICAL = 3
|
||||
const val WEBTOON = 4
|
||||
|
||||
const val BLACK_THEME = 1
|
||||
|
||||
const val MENU_VISIBLE = "menu_visible"
|
||||
|
||||
fun newIntent(context: Context): Intent {
|
||||
return Intent(context, ReaderActivity::class.java)
|
||||
}
|
||||
}
|
||||
|
||||
private var viewer: BaseReader? = null
|
||||
|
||||
private var uiFlags: Int = 0
|
||||
|
||||
lateinit var subscriptions: CompositeSubscription
|
||||
private set
|
||||
|
||||
private var customBrightnessSubscription: Subscription? = null
|
||||
|
||||
var readerTheme: Int = 0
|
||||
private set
|
||||
|
||||
var maxBitmapSize: Int = 0
|
||||
private set
|
||||
|
||||
private val decimalFormat = DecimalFormat("#.###")
|
||||
|
||||
private var popupMenu: ReaderPopupMenu? = null
|
||||
|
||||
private var nextChapterBtn: MenuItem? = null
|
||||
|
||||
private var prevChapterBtn: MenuItem? = null
|
||||
|
||||
val preferences: PreferencesHelper
|
||||
get() = presenter.prefs
|
||||
|
||||
public override fun onCreate(savedState: Bundle?) {
|
||||
super.onCreate(savedState)
|
||||
setContentView(R.layout.activity_reader)
|
||||
|
||||
setupToolbar(toolbar)
|
||||
subscriptions = CompositeSubscription()
|
||||
|
||||
initializeMenu()
|
||||
initializeSettings()
|
||||
|
||||
if (savedState != null) {
|
||||
setMenuVisibility(savedState.getBoolean(MENU_VISIBLE), animate = false)
|
||||
}
|
||||
|
||||
maxBitmapSize = GLUtil.getMaxTextureSize()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
setSystemUiVisibility()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
viewer?.let {
|
||||
presenter.currentPage = it.getActivePage()
|
||||
}
|
||||
super.onPause()
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
subscriptions.unsubscribe()
|
||||
popupMenu?.dismiss()
|
||||
viewer = null
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.reader, menu)
|
||||
nextChapterBtn = menu.findItem(R.id.action_next_chapter)
|
||||
prevChapterBtn = menu.findItem(R.id.action_previous_chapter)
|
||||
setAdjacentChaptersVisibility()
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_previous_chapter -> requestPreviousChapter()
|
||||
R.id.action_next_chapter -> requestNextChapter()
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
outState.putBoolean(MENU_VISIBLE, reader_menu.visibility == View.VISIBLE)
|
||||
super.onSaveInstanceState(outState)
|
||||
}
|
||||
|
||||
override fun onBackPressed() {
|
||||
presenter.onChapterLeft()
|
||||
|
||||
val chapterToUpdate = presenter.mangaSyncChapterToUpdate
|
||||
|
||||
if (chapterToUpdate > 0) {
|
||||
if (presenter.prefs.askUpdateMangaSync()) {
|
||||
MaterialDialog.Builder(this)
|
||||
.content(getString(R.string.confirm_update_manga_sync, chapterToUpdate))
|
||||
.positiveText(android.R.string.yes)
|
||||
.negativeText(android.R.string.no)
|
||||
.onPositive { dialog, which -> presenter.updateMangaSyncLastChapterRead() }
|
||||
.onAny { dialog1, which1 -> finish() }
|
||||
.show()
|
||||
} else {
|
||||
presenter.updateMangaSyncLastChapterRead()
|
||||
finish()
|
||||
}
|
||||
} else {
|
||||
super.onBackPressed()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onWindowFocusChanged(hasFocus: Boolean) {
|
||||
super.onWindowFocusChanged(hasFocus)
|
||||
if (hasFocus) {
|
||||
setSystemUiVisibility()
|
||||
}
|
||||
}
|
||||
|
||||
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
|
||||
val action = event.action
|
||||
val keyCode = event.keyCode
|
||||
when (keyCode) {
|
||||
KeyEvent.KEYCODE_VOLUME_DOWN -> {
|
||||
if (action == KeyEvent.ACTION_UP)
|
||||
viewer?.moveToNext()
|
||||
return true
|
||||
}
|
||||
KeyEvent.KEYCODE_VOLUME_UP -> {
|
||||
if (action == KeyEvent.ACTION_UP)
|
||||
viewer?.moveToPrevious()
|
||||
return true
|
||||
}
|
||||
else -> return super.dispatchKeyEvent(event)
|
||||
}
|
||||
}
|
||||
|
||||
fun onChapterError() {
|
||||
finish()
|
||||
toast(R.string.page_list_error)
|
||||
}
|
||||
|
||||
fun onChapterAppendError() {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
fun onChapterReady(manga: Manga, chapter: Chapter, currentPage: Page?) {
|
||||
val activePage = currentPage ?: chapter.pages.last()
|
||||
|
||||
if (viewer == null) {
|
||||
viewer = getOrCreateViewer(manga)
|
||||
}
|
||||
viewer?.onPageListReady(chapter, activePage)
|
||||
|
||||
if (viewer is RightToLeftReader && page_seekbar.rotation != 180f) {
|
||||
// Invert the seekbar for the right to left reader
|
||||
page_seekbar.rotation = 180f
|
||||
}
|
||||
setToolbarTitle(manga.title)
|
||||
setActiveChapter(chapter, activePage.pageNumber)
|
||||
}
|
||||
|
||||
fun onEnterChapter(chapter: Chapter, currentPage: Int) {
|
||||
val activePage = if (currentPage == -1) chapter.pages.lastIndex else currentPage
|
||||
presenter.setActiveChapter(chapter)
|
||||
setActiveChapter(chapter, activePage)
|
||||
}
|
||||
|
||||
fun setActiveChapter(chapter: Chapter, currentPage: Int) {
|
||||
val numPages = chapter.pages.size
|
||||
if (page_seekbar.rotation != 180f) {
|
||||
right_page_text.text = "$numPages"
|
||||
left_page_text.text = "${currentPage + 1}"
|
||||
} else {
|
||||
left_page_text.text = "$numPages"
|
||||
right_page_text.text = "${currentPage + 1}"
|
||||
}
|
||||
page_seekbar.max = numPages - 1
|
||||
page_seekbar.progress = currentPage
|
||||
|
||||
setToolbarSubtitle(if (chapter.chapter_number != -1f)
|
||||
getString(R.string.chapter_subtitle, decimalFormat.format(chapter.chapter_number.toDouble()))
|
||||
else
|
||||
chapter.name)
|
||||
}
|
||||
|
||||
fun onAppendChapter(chapter: Chapter) {
|
||||
viewer?.onPageListAppendReady(chapter)
|
||||
}
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
fun onAdjacentChapters(previous: Chapter, next: Chapter) {
|
||||
setAdjacentChaptersVisibility()
|
||||
}
|
||||
|
||||
private fun setAdjacentChaptersVisibility() {
|
||||
prevChapterBtn?.isVisible = presenter.hasPreviousChapter()
|
||||
nextChapterBtn?.isVisible = presenter.hasNextChapter()
|
||||
}
|
||||
|
||||
private fun getOrCreateViewer(manga: Manga): BaseReader {
|
||||
val mangaViewer = if (manga.viewer == 0) preferences.defaultViewer else manga.viewer
|
||||
|
||||
// Try to reuse the viewer using its tag
|
||||
var fragment: BaseReader? = supportFragmentManager.findFragmentByTag(manga.viewer.toString()) as? BaseReader
|
||||
if (fragment == null) {
|
||||
// Create a new viewer
|
||||
when (mangaViewer) {
|
||||
RIGHT_TO_LEFT -> fragment = RightToLeftReader()
|
||||
VERTICAL -> fragment = VerticalReader()
|
||||
WEBTOON -> fragment = WebtoonReader()
|
||||
else -> fragment = LeftToRightReader()
|
||||
}
|
||||
|
||||
supportFragmentManager.beginTransaction().replace(R.id.reader, fragment, manga.viewer.toString()).commit()
|
||||
}
|
||||
return fragment
|
||||
}
|
||||
|
||||
fun onPageChanged(currentPageIndex: Int, totalPages: Int) {
|
||||
val page = currentPageIndex + 1
|
||||
page_number.text = "$page/$totalPages"
|
||||
if (page_seekbar.rotation != 180f) {
|
||||
left_page_text.text = "$page"
|
||||
} else {
|
||||
right_page_text.text = "$page"
|
||||
}
|
||||
page_seekbar.progress = currentPageIndex
|
||||
}
|
||||
|
||||
fun gotoPageInCurrentChapter(pageIndex: Int) {
|
||||
viewer?.let {
|
||||
val requestedPage = it.getActivePage().chapter.pages[pageIndex]
|
||||
it.setActivePage(requestedPage)
|
||||
}
|
||||
}
|
||||
|
||||
fun onCenterSingleTap() {
|
||||
setMenuVisibility(reader_menu.visibility == View.GONE)
|
||||
}
|
||||
|
||||
fun requestNextChapter() {
|
||||
if (!presenter.loadNextChapter()) {
|
||||
toast(R.string.no_next_chapter)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestPreviousChapter() {
|
||||
if (!presenter.loadPreviousChapter()) {
|
||||
toast(R.string.no_previous_chapter)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setMenuVisibility(visible: Boolean, animate: Boolean = true) {
|
||||
if (visible) {
|
||||
reader_menu.visibility = View.VISIBLE
|
||||
|
||||
if (animate) {
|
||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_top)
|
||||
toolbar.startAnimation(toolbarAnimation)
|
||||
|
||||
val bottomMenuAnimation = AnimationUtils.loadAnimation(this, R.anim.enter_from_bottom)
|
||||
reader_menu_bottom.startAnimation(bottomMenuAnimation)
|
||||
}
|
||||
} else {
|
||||
val toolbarAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_top)
|
||||
toolbarAnimation.setAnimationListener(object : SimpleAnimationListener() {
|
||||
override fun onAnimationEnd(animation: Animation) {
|
||||
reader_menu.visibility = View.GONE
|
||||
}
|
||||
})
|
||||
toolbar.startAnimation(toolbarAnimation)
|
||||
|
||||
val bottomMenuAnimation = AnimationUtils.loadAnimation(this, R.anim.exit_to_bottom)
|
||||
reader_menu_bottom.startAnimation(bottomMenuAnimation)
|
||||
|
||||
popupMenu?.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private fun initializeMenu() {
|
||||
// Intercept all events in this layout
|
||||
reader_menu_bottom.setOnTouchListener { v, event -> true }
|
||||
|
||||
page_seekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
gotoPageInCurrentChapter(progress)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
lock_orientation.setOnClickListener { v ->
|
||||
showImmersiveDialog(MaterialDialog.Builder(this)
|
||||
.title(R.string.pref_rotation_type)
|
||||
.items(R.array.rotation_type)
|
||||
.itemsCallbackSingleChoice(preferences.rotation().getOrDefault() - 1,
|
||||
{ d, itemView, which, text ->
|
||||
preferences.rotation().set(which + 1)
|
||||
true
|
||||
})
|
||||
.build())
|
||||
}
|
||||
|
||||
reader_zoom_selector.setOnClickListener { v ->
|
||||
showImmersiveDialog(MaterialDialog.Builder(this)
|
||||
.title(R.string.pref_zoom_start)
|
||||
.items(R.array.zoom_start)
|
||||
.itemsCallbackSingleChoice(preferences.zoomStart().getOrDefault() - 1,
|
||||
{ d, itemView, which, text ->
|
||||
preferences.zoomStart().set(which + 1)
|
||||
true
|
||||
})
|
||||
.build())
|
||||
}
|
||||
|
||||
reader_scale_type_selector.setOnClickListener { v ->
|
||||
showImmersiveDialog(MaterialDialog.Builder(this)
|
||||
.title(R.string.pref_image_scale_type)
|
||||
.items(R.array.image_scale_type)
|
||||
.itemsCallbackSingleChoice(preferences.imageScaleType().getOrDefault() - 1,
|
||||
{ d, itemView, which, text ->
|
||||
preferences.imageScaleType().set(which + 1)
|
||||
true
|
||||
})
|
||||
.build())
|
||||
}
|
||||
|
||||
reader_selector.setOnClickListener { v ->
|
||||
showImmersiveDialog(MaterialDialog.Builder(this)
|
||||
.title(R.string.pref_viewer_type)
|
||||
.items(R.array.viewers_selector)
|
||||
.itemsCallbackSingleChoice(presenter.manga.viewer,
|
||||
{ d, itemView, which, text ->
|
||||
presenter.updateMangaViewer(which)
|
||||
recreate()
|
||||
true
|
||||
})
|
||||
.build())
|
||||
}
|
||||
|
||||
val popupView = layoutInflater.inflate(R.layout.reader_popup, null)
|
||||
popupMenu = ReaderPopupMenu(this, popupView)
|
||||
|
||||
reader_extra_settings.setOnClickListener {
|
||||
popupMenu?.let {
|
||||
if (!it.isShowing)
|
||||
it.showAtLocation(reader_extra_settings,
|
||||
Gravity.BOTTOM or Gravity.RIGHT, 0, reader_menu_bottom.height)
|
||||
else
|
||||
it.dismiss()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun initializeSettings() {
|
||||
subscriptions.add(preferences.showPageNumber().asObservable()
|
||||
.subscribe { setPageNumberVisibility(it) })
|
||||
|
||||
subscriptions.add(preferences.rotation().asObservable()
|
||||
.subscribe {
|
||||
setRotation(it)
|
||||
|
||||
val isPortrait = resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
|
||||
|
||||
val resourceId = if (it == 1)
|
||||
R.drawable.ic_screen_rotation_white_24dp
|
||||
else if (isPortrait)
|
||||
R.drawable.ic_screen_lock_portrait_white_24dp
|
||||
else
|
||||
R.drawable.ic_screen_lock_landscape_white_24dp
|
||||
|
||||
lock_orientation.setImageResource(resourceId)
|
||||
})
|
||||
|
||||
subscriptions.add(preferences.hideStatusBar().asObservable()
|
||||
.subscribe { setStatusBarVisibility(it) })
|
||||
|
||||
subscriptions.add(preferences.keepScreenOn().asObservable()
|
||||
.subscribe { setKeepScreenOn(it) })
|
||||
|
||||
subscriptions.add(preferences.customBrightness().asObservable()
|
||||
.subscribe { setCustomBrightness(it) })
|
||||
|
||||
subscriptions.add(preferences.readerTheme().asObservable()
|
||||
.distinctUntilChanged()
|
||||
.subscribe { applyTheme(it) })
|
||||
}
|
||||
|
||||
private fun setRotation(rotation: Int) {
|
||||
when (rotation) {
|
||||
// Rotation free
|
||||
1 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
||||
// Lock in current rotation
|
||||
2 -> {
|
||||
val currentOrientation = resources.configuration.orientation
|
||||
setRotation(if (currentOrientation == Configuration.ORIENTATION_PORTRAIT) 3 else 4)
|
||||
}
|
||||
// Lock in portrait
|
||||
3 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT
|
||||
// Lock in landscape
|
||||
4 -> requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE
|
||||
}
|
||||
}
|
||||
|
||||
private fun setPageNumberVisibility(visible: Boolean) {
|
||||
page_number.visibility = if (visible) View.VISIBLE else View.INVISIBLE
|
||||
}
|
||||
|
||||
private fun setKeepScreenOn(enabled: Boolean) {
|
||||
if (enabled) {
|
||||
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
} else {
|
||||
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCustomBrightness(enabled: Boolean) {
|
||||
if (enabled) {
|
||||
customBrightnessSubscription = preferences.customBrightnessValue().asObservable()
|
||||
.subscribe { setCustomBrightnessValue(it) }
|
||||
|
||||
subscriptions.add(customBrightnessSubscription)
|
||||
} else {
|
||||
if (customBrightnessSubscription != null)
|
||||
subscriptions.remove(customBrightnessSubscription)
|
||||
setCustomBrightnessValue(-1f)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setCustomBrightnessValue(value: Float) {
|
||||
window.attributes = window.attributes.apply { screenBrightness = value }
|
||||
}
|
||||
|
||||
private fun setStatusBarVisibility(hidden: Boolean) {
|
||||
createUiHideFlags(hidden)
|
||||
setSystemUiVisibility()
|
||||
}
|
||||
|
||||
private fun createUiHideFlags(statusBarHidden: Boolean) {
|
||||
uiFlags = 0
|
||||
uiFlags = uiFlags or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
|
||||
if (statusBarHidden) {
|
||||
uiFlags = uiFlags or View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
||||
View.SYSTEM_UI_FLAG_FULLSCREEN
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
uiFlags = uiFlags or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
||||
}
|
||||
}
|
||||
|
||||
fun setSystemUiVisibility() {
|
||||
window.decorView.systemUiVisibility = uiFlags
|
||||
}
|
||||
|
||||
private fun applyTheme(theme: Int) {
|
||||
readerTheme = theme
|
||||
val rootView = window.decorView.rootView
|
||||
if (theme == BLACK_THEME) {
|
||||
rootView.setBackgroundColor(Color.BLACK)
|
||||
page_number.setTextColor(ContextCompat.getColor(this, R.color.textColorPrimaryDark))
|
||||
page_number.setBackgroundColor(ContextCompat.getColor(this, R.color.backgroundDark))
|
||||
} else {
|
||||
rootView.setBackgroundColor(Color.WHITE)
|
||||
page_number.setTextColor(ContextCompat.getColor(this, R.color.textColorPrimaryLight))
|
||||
page_number.setBackgroundColor(ContextCompat.getColor(this, R.color.backgroundLight))
|
||||
}
|
||||
}
|
||||
|
||||
private fun showImmersiveDialog(dialog: Dialog) {
|
||||
// Hack to not leave immersive mode
|
||||
dialog.window.setFlags(FLAG_NOT_FOCUSABLE, FLAG_NOT_FOCUSABLE)
|
||||
dialog.show()
|
||||
dialog.window.decorView.systemUiVisibility = window.decorView.systemUiVisibility
|
||||
dialog.window.clearFlags(FLAG_NOT_FOCUSABLE)
|
||||
}
|
||||
|
||||
}
|
|
@ -1,421 +0,0 @@
|
|||
package eu.kanade.tachiyomi.ui.reader;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.res.Configuration;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.Gravity;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager.LayoutParams;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.AnimationUtils;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.SeekBar;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
|
||||
import butterknife.Bind;
|
||||
import butterknife.ButterKnife;
|
||||
import eu.kanade.tachiyomi.R;
|
||||
import eu.kanade.tachiyomi.data.database.models.Chapter;
|
||||
import eu.kanade.tachiyomi.data.database.models.Manga;
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper;
|
||||
import icepick.State;
|
||||
import rx.Subscription;
|
||||
|
||||
public class ReaderMenu {
|
||||
|
||||
@Bind(R.id.reader_menu) RelativeLayout menu;
|
||||
@Bind(R.id.reader_menu_bottom) LinearLayout bottomMenu;
|
||||
@Bind(R.id.toolbar) Toolbar toolbar;
|
||||
@Bind(R.id.current_page) TextView currentPage;
|
||||
@Bind(R.id.page_seeker) SeekBar seekBar;
|
||||
@Bind(R.id.total_pages) TextView totalPages;
|
||||
@Bind(R.id.lock_orientation) ImageButton lockOrientation;
|
||||
@Bind(R.id.reader_zoom_selector) ImageButton zoomSelector;
|
||||
@Bind(R.id.reader_scale_type_selector) ImageButton scaleTypeSelector;
|
||||
@Bind(R.id.reader_selector) ImageButton readerSelector;
|
||||
@Bind(R.id.reader_extra_settings) ImageButton extraSettings;
|
||||
|
||||
private MenuItem nextChapterBtn;
|
||||
private MenuItem prevChapterBtn;
|
||||
private Chapter prevChapter;
|
||||
private Chapter nextChapter;
|
||||
|
||||
private ReaderActivity activity;
|
||||
private PreferencesHelper preferences;
|
||||
|
||||
@State boolean showing;
|
||||
private PopupWindow settingsPopup;
|
||||
private boolean inverted;
|
||||
|
||||
private DecimalFormat decimalFormat;
|
||||
|
||||
public ReaderMenu(ReaderActivity activity) {
|
||||
this.activity = activity;
|
||||
this.preferences = activity.getPreferences();
|
||||
ButterKnife.bind(this, activity);
|
||||
|
||||
// Intercept all image events in this layout
|
||||
bottomMenu.setOnTouchListener((v, event) -> true);
|
||||
|
||||
seekBar.setOnSeekBarChangeListener(new PageSeekBarChangeListener());
|
||||
decimalFormat = new DecimalFormat("#.###");
|
||||
inverted = false;
|
||||
|
||||
initializeMenu();
|
||||
}
|
||||
|
||||
public void add(Subscription subscription) {
|
||||
activity.subscriptions.add(subscription);
|
||||
}
|
||||
|
||||
public void toggle() {
|
||||
if (showing)
|
||||
hide();
|
||||
else
|
||||
show(true);
|
||||
}
|
||||
|
||||
public void show(boolean animate) {
|
||||
menu.setVisibility(View.VISIBLE);
|
||||
|
||||
if (animate) {
|
||||
Animation toolbarAnimation = AnimationUtils.loadAnimation(activity, R.anim.enter_from_top);
|
||||
toolbar.startAnimation(toolbarAnimation);
|
||||
|
||||
Animation bottomMenuAnimation = AnimationUtils.loadAnimation(activity, R.anim.enter_from_bottom);
|
||||
bottomMenu.startAnimation(bottomMenuAnimation);
|
||||
}
|
||||
|
||||
showing = true;
|
||||
}
|
||||
|
||||
public void hide() {
|
||||
Animation toolbarAnimation = AnimationUtils.loadAnimation(activity, R.anim.exit_to_top);
|
||||
toolbarAnimation.setAnimationListener(new HideMenuAnimationListener());
|
||||
toolbar.startAnimation(toolbarAnimation);
|
||||
|
||||
Animation bottomMenuAnimation = AnimationUtils.loadAnimation(activity, R.anim.exit_to_bottom);
|
||||
bottomMenu.startAnimation(bottomMenuAnimation);
|
||||
|
||||
settingsPopup.dismiss();
|
||||
|
||||
showing = false;
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
if (settingsPopup != null) {
|
||||
settingsPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
activity.getMenuInflater().inflate(R.menu.reader, menu);
|
||||
nextChapterBtn = menu.findItem(R.id.action_next_chapter);
|
||||
prevChapterBtn = menu.findItem(R.id.action_previous_chapter);
|
||||
setAdjacentChaptersVisibility();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item == prevChapterBtn) {
|
||||
activity.requestPreviousChapter();
|
||||
} else if (item == nextChapterBtn) {
|
||||
activity.requestNextChapter();
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setActiveManga(Manga manga) {
|
||||
if (manga.viewer == ReaderActivity.RIGHT_TO_LEFT && !inverted) {
|
||||
// Invert the seekbar and textview fields for the right to left reader
|
||||
seekBar.setRotation(180);
|
||||
TextView aux = currentPage;
|
||||
currentPage = totalPages;
|
||||
totalPages = aux;
|
||||
// Don't invert again on chapter change
|
||||
inverted = true;
|
||||
}
|
||||
activity.setToolbarTitle(manga.title);
|
||||
}
|
||||
|
||||
public void setActiveChapter(Chapter chapter, int currentPageIndex) {
|
||||
// Set initial values
|
||||
int numPages = chapter.getPages().size();
|
||||
totalPages.setText("" + numPages);
|
||||
currentPage.setText("" + (currentPageIndex + 1));
|
||||
seekBar.setMax(numPages - 1);
|
||||
seekBar.setProgress(currentPageIndex);
|
||||
|
||||
activity.setToolbarSubtitle(chapter.chapter_number != -1 ?
|
||||
activity.getString(R.string.chapter_subtitle,
|
||||
decimalFormat.format(chapter.chapter_number)) :
|
||||
chapter.name);
|
||||
|
||||
}
|
||||
|
||||
public void onPageChanged(int pageIndex) {
|
||||
currentPage.setText("" + (pageIndex + 1));
|
||||
seekBar.setProgress(pageIndex);
|
||||
}
|
||||
|
||||
public void onAdjacentChapters(Chapter previous, Chapter next) {
|
||||
prevChapter = previous;
|
||||
nextChapter = next;
|
||||
setAdjacentChaptersVisibility();
|
||||
}
|
||||
|
||||
private void setAdjacentChaptersVisibility() {
|
||||
if (prevChapterBtn != null) prevChapterBtn.setVisible(prevChapter != null);
|
||||
if (nextChapterBtn != null) nextChapterBtn.setVisible(nextChapter != null);
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private void initializeMenu() {
|
||||
// Orientation selector
|
||||
add(preferences.rotation().asObservable()
|
||||
.subscribe(value -> {
|
||||
boolean isPortrait = activity.getResources().getConfiguration()
|
||||
.orientation == Configuration.ORIENTATION_PORTRAIT;
|
||||
int resourceId = value == 1 ? R.drawable.ic_screen_rotation_white_24dp : isPortrait ?
|
||||
R.drawable.ic_screen_lock_portrait_white_24dp :
|
||||
R.drawable.ic_screen_lock_landscape_white_24dp;
|
||||
|
||||
lockOrientation.setImageResource(resourceId);
|
||||
}));
|
||||
|
||||
lockOrientation.setOnClickListener(v -> {
|
||||
showImmersiveDialog(new MaterialDialog.Builder(activity)
|
||||
.title(R.string.pref_rotation_type)
|
||||
.items(R.array.rotation_type)
|
||||
.itemsCallbackSingleChoice(preferences.rotation().get() - 1,
|
||||
(d, itemView, which, text) -> {
|
||||
preferences.rotation().set(which + 1);
|
||||
return true;
|
||||
})
|
||||
.build());
|
||||
});
|
||||
|
||||
// Zoom selector
|
||||
zoomSelector.setOnClickListener(v -> {
|
||||
showImmersiveDialog(new MaterialDialog.Builder(activity)
|
||||
.title(R.string.pref_zoom_start)
|
||||
.items(R.array.zoom_start)
|
||||
.itemsCallbackSingleChoice(preferences.zoomStart().get() - 1,
|
||||
(d, itemView, which, text) -> {
|
||||
preferences.zoomStart().set(which + 1);
|
||||
return true;
|
||||
})
|
||||
.build());
|
||||
});
|
||||
|
||||
// Scale type selector
|
||||
scaleTypeSelector.setOnClickListener(v -> {
|
||||
showImmersiveDialog(new MaterialDialog.Builder(activity)
|
||||
.title(R.string.pref_image_scale_type)
|
||||
.items(R.array.image_scale_type)
|
||||
.itemsCallbackSingleChoice(preferences.imageScaleType().get() - 1,
|
||||
(d, itemView, which, text) -> {
|
||||
preferences.imageScaleType().set(which + 1);
|
||||
return true;
|
||||
})
|
||||
.build());
|
||||
});
|
||||
|
||||
// Reader selector
|
||||
readerSelector.setOnClickListener(v -> {
|
||||
final Manga manga = activity.getPresenter().getManga();
|
||||
showImmersiveDialog(new MaterialDialog.Builder(activity)
|
||||
.title(R.string.pref_viewer_type)
|
||||
.items(R.array.viewers_selector)
|
||||
.itemsCallbackSingleChoice(manga.viewer,
|
||||
(d, itemView, which, text) -> {
|
||||
activity.setMangaDefaultViewer(which);
|
||||
return true;
|
||||
})
|
||||
.build());
|
||||
});
|
||||
|
||||
// Extra settings menu
|
||||
final View popupView = activity.getLayoutInflater().inflate(R.layout.reader_popup, null);
|
||||
settingsPopup = new SettingsPopupWindow(popupView);
|
||||
|
||||
extraSettings.setOnClickListener(v -> {
|
||||
if (!settingsPopup.isShowing())
|
||||
settingsPopup.showAtLocation(extraSettings,
|
||||
Gravity.BOTTOM | Gravity.RIGHT, 0, bottomMenu.getHeight());
|
||||
else
|
||||
settingsPopup.dismiss();
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
private void showImmersiveDialog(Dialog dialog) {
|
||||
// Hack to not leave immersive mode
|
||||
dialog.getWindow().setFlags(LayoutParams.FLAG_NOT_FOCUSABLE, LayoutParams.FLAG_NOT_FOCUSABLE);
|
||||
dialog.show();
|
||||
dialog.getWindow().getDecorView().setSystemUiVisibility(
|
||||
activity.getWindow().getDecorView().getSystemUiVisibility());
|
||||
dialog.getWindow().clearFlags(LayoutParams.FLAG_NOT_FOCUSABLE);
|
||||
}
|
||||
|
||||
class SettingsPopupWindow extends PopupWindow {
|
||||
|
||||
@Bind(R.id.enable_transitions) CheckBox enableTransitions;
|
||||
@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.reader_theme) CheckBox readerTheme;
|
||||
@Bind(R.id.image_decoder_container) ViewGroup imageDecoderContainer;
|
||||
@Bind(R.id.image_decoder) TextView imageDecoder;
|
||||
@Bind(R.id.image_decoder_initial) TextView imageDecoderInitial;
|
||||
@Bind(R.id.custom_brightness) CheckBox customBrightness;
|
||||
@Bind(R.id.brightness_seekbar) SeekBar brightnessSeekbar;
|
||||
|
||||
public SettingsPopupWindow(View view) {
|
||||
super(view, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
|
||||
setAnimationStyle(R.style.reader_settings_popup_animation);
|
||||
ButterKnife.bind(this, view);
|
||||
initializePopupMenu();
|
||||
}
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private void initializePopupMenu() {
|
||||
// Load values from preferences
|
||||
enableTransitions.setChecked(preferences.enableTransitions().get());
|
||||
showPageNumber.setChecked(preferences.showPageNumber().get());
|
||||
hideStatusBar.setChecked(preferences.hideStatusBar().get());
|
||||
keepScreenOn.setChecked(preferences.keepScreenOn().get());
|
||||
readerTheme.setChecked(preferences.readerTheme().get() == 1);
|
||||
setDecoderInitial(preferences.imageDecoder().get());
|
||||
|
||||
// Add a listener to change the corresponding setting
|
||||
enableTransitions.setOnCheckedChangeListener((view, isChecked) ->
|
||||
preferences.enableTransitions().set(isChecked));
|
||||
|
||||
showPageNumber.setOnCheckedChangeListener((view, isChecked) ->
|
||||
preferences.showPageNumber().set(isChecked));
|
||||
|
||||
hideStatusBar.setOnCheckedChangeListener((view, isChecked) ->
|
||||
preferences.hideStatusBar().set(isChecked));
|
||||
|
||||
keepScreenOn.setOnCheckedChangeListener((view, isChecked) ->
|
||||
preferences.keepScreenOn().set(isChecked));
|
||||
|
||||
readerTheme.setOnCheckedChangeListener((view, isChecked) ->
|
||||
preferences.readerTheme().set(isChecked ? 1 : 0));
|
||||
|
||||
imageDecoderContainer.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);
|
||||
setDecoderInitial(which);
|
||||
return true;
|
||||
})
|
||||
.build());
|
||||
});
|
||||
|
||||
add(preferences.customBrightness()
|
||||
.asObservable()
|
||||
.subscribe(isEnabled -> {
|
||||
customBrightness.setChecked(isEnabled);
|
||||
brightnessSeekbar.setEnabled(isEnabled);
|
||||
}));
|
||||
|
||||
customBrightness.setOnCheckedChangeListener((view, isChecked) ->
|
||||
preferences.customBrightness().set(isChecked));
|
||||
|
||||
brightnessSeekbar.setMax(100);
|
||||
brightnessSeekbar.setProgress(Math.round(
|
||||
preferences.customBrightnessValue().get() * brightnessSeekbar.getMax()));
|
||||
brightnessSeekbar.setOnSeekBarChangeListener(new BrightnessSeekBarChangeListener());
|
||||
}
|
||||
|
||||
private void setDecoderInitial(int decoder) {
|
||||
String initial;
|
||||
switch (decoder) {
|
||||
case 0:
|
||||
initial = "R";
|
||||
break;
|
||||
case 1:
|
||||
initial = "S";
|
||||
break;
|
||||
default:
|
||||
initial = "";
|
||||
break;
|
||||
}
|
||||
imageDecoderInitial.setText(initial);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PageSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (fromUser) {
|
||||
activity.gotoPageInCurrentChapter(progress);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {}
|
||||
}
|
||||
|
||||
class BrightnessSeekBarChangeListener implements SeekBar.OnSeekBarChangeListener {
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (fromUser) {
|
||||
preferences.customBrightnessValue().set((float) progress / seekBar.getMax());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
class HideMenuAnimationListener implements Animation.AnimationListener {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animation animation) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animation animation) {
|
||||
menu.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animation animation) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
package eu.kanade.tachiyomi.ui.reader
|
||||
|
||||
import android.app.Dialog
|
||||
import android.view.View
|
||||
import android.view.ViewGroup.LayoutParams.WRAP_CONTENT
|
||||
import android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
|
||||
import android.widget.PopupWindow
|
||||
import android.widget.SeekBar
|
||||
import com.afollestad.materialdialogs.MaterialDialog
|
||||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.data.preference.getOrDefault
|
||||
import eu.kanade.tachiyomi.ui.base.listener.SimpleSeekBarListener
|
||||
import kotlinx.android.synthetic.main.reader_popup.view.*
|
||||
import java.lang.ref.WeakReference
|
||||
|
||||
class ReaderPopupMenu(activity: ReaderActivity, val view: View) : PopupWindow(view, WRAP_CONTENT, WRAP_CONTENT) {
|
||||
|
||||
val activity = WeakReference(activity)
|
||||
|
||||
init {
|
||||
animationStyle = R.style.reader_settings_popup_animation
|
||||
setValues(activity.preferences)
|
||||
}
|
||||
|
||||
private fun setValues(preferences: PreferencesHelper) = with(view) {
|
||||
enable_transitions.isChecked = preferences.enableTransitions().getOrDefault()
|
||||
show_page_number.isChecked = preferences.showPageNumber().getOrDefault()
|
||||
hide_status_bar.isChecked = preferences.hideStatusBar().getOrDefault()
|
||||
keep_screen_on.isChecked = preferences.keepScreenOn().getOrDefault()
|
||||
reader_theme.isChecked = preferences.readerTheme().getOrDefault() == 1
|
||||
|
||||
setDecoderInitial(preferences.imageDecoder().getOrDefault())
|
||||
|
||||
// Add a listener to change the corresponding setting
|
||||
enable_transitions.setOnCheckedChangeListener { v, isChecked ->
|
||||
preferences.enableTransitions().set(isChecked)
|
||||
}
|
||||
|
||||
show_page_number.setOnCheckedChangeListener { v, isChecked ->
|
||||
preferences.showPageNumber().set(isChecked)
|
||||
}
|
||||
|
||||
hide_status_bar.setOnCheckedChangeListener { v, isChecked ->
|
||||
preferences.hideStatusBar().set(isChecked)
|
||||
}
|
||||
|
||||
keep_screen_on.setOnCheckedChangeListener { v, isChecked ->
|
||||
preferences.keepScreenOn().set(isChecked)
|
||||
}
|
||||
|
||||
reader_theme.setOnCheckedChangeListener { v, isChecked ->
|
||||
preferences.readerTheme().set(if (isChecked) 1 else 0)
|
||||
}
|
||||
|
||||
image_decoder_container.setOnClickListener { v ->
|
||||
showImmersiveDialog(MaterialDialog.Builder(view.context)
|
||||
.title(R.string.pref_image_decoder)
|
||||
.items(R.array.image_decoders)
|
||||
.itemsCallbackSingleChoice(preferences.imageDecoder().getOrDefault(), { dialog, itemView, which, text ->
|
||||
preferences.imageDecoder().set(which)
|
||||
setDecoderInitial(which)
|
||||
true
|
||||
})
|
||||
.build())
|
||||
}
|
||||
|
||||
activity.get().subscriptions.add(preferences.customBrightness().asObservable()
|
||||
.subscribe { isEnabled ->
|
||||
custom_brightness.isChecked = isEnabled
|
||||
brightness_seekbar.isEnabled = isEnabled
|
||||
})
|
||||
|
||||
custom_brightness.setOnCheckedChangeListener { v, isChecked ->
|
||||
preferences.customBrightness().set(isChecked)
|
||||
}
|
||||
|
||||
brightness_seekbar.max = 100
|
||||
brightness_seekbar.progress = Math.round(
|
||||
preferences.customBrightnessValue().getOrDefault() * brightness_seekbar.max)
|
||||
brightness_seekbar.setOnSeekBarChangeListener(object : SimpleSeekBarListener() {
|
||||
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
|
||||
if (fromUser) {
|
||||
preferences.customBrightnessValue().set(progress.toFloat() / seekBar.max)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun setDecoderInitial(decoder: Int) {
|
||||
val initial: String
|
||||
when (decoder) {
|
||||
0 -> initial = "R"
|
||||
1 -> initial = "S"
|
||||
else -> initial = ""
|
||||
}
|
||||
view.image_decoder_initial.text = initial
|
||||
}
|
||||
|
||||
private fun showImmersiveDialog(dialog: Dialog) {
|
||||
// Hack to not leave immersive mode
|
||||
dialog.window.setFlags(FLAG_NOT_FOCUSABLE, FLAG_NOT_FOCUSABLE)
|
||||
dialog.show()
|
||||
dialog.window.decorView.systemUiVisibility = activity.get().window.decorView.systemUiVisibility
|
||||
dialog.window.clearFlags(FLAG_NOT_FOCUSABLE)
|
||||
}
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ import com.dd.processbutton.iml.ActionProcessButton
|
|||
import eu.kanade.tachiyomi.R
|
||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||
import eu.kanade.tachiyomi.ui.setting.SettingsActivity
|
||||
import eu.kanade.tachiyomi.widget.SimpleTextWatcher
|
||||
import eu.kanade.tachiyomi.ui.base.listener.SimpleTextWatcher
|
||||
import kotlinx.android.synthetic.main.pref_account_login.view.*
|
||||
import rx.Subscription
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
android:layout_height="?attr/actionBarSize">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/current_page"
|
||||
android:id="@+id/left_page_text"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -40,7 +40,7 @@
|
|||
android:textSize="15sp"/>
|
||||
|
||||
<SeekBar
|
||||
android:id="@+id/page_seeker"
|
||||
android:id="@+id/page_seekbar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
@ -48,7 +48,7 @@
|
|||
/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/total_pages"
|
||||
android:id="@+id/right_page_text"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
|
|
@ -6,7 +6,7 @@ buildscript {
|
|||
jcenter()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:2.1.0-alpha1'
|
||||
classpath 'com.android.tools.build:gradle:2.1.0-alpha3'
|
||||
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
|
||||
classpath 'me.tatarka:gradle-retrolambda:3.2.4'
|
||||
classpath 'com.github.ben-manes:gradle-versions-plugin:0.12.0'
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
|
|||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.12-all.zip
|
||||
|
|
Reference in a new issue