From 4ccce424defc67505f18aea4bd3c615690d521ec Mon Sep 17 00:00:00 2001 From: len Date: Fri, 18 Mar 2016 20:21:30 +0100 Subject: [PATCH] Reader view in Kotlin. Upgrade gradle wrapper. Remove ButterKnife from the project --- app/build.gradle | 1 - app/src/main/AndroidManifest.xml | 3 +- .../base/listener/SimpleAnimationListener.kt | 11 + .../ui/base/listener/SimpleSeekBarListener.kt | 11 + .../base/listener}/SimpleTextWatcher.kt | 2 +- .../myanimelist/MyAnimeListDialogFragment.kt | 2 +- .../tachiyomi/ui/reader/ReaderActivity.java | 423 -------------- .../tachiyomi/ui/reader/ReaderActivity.kt | 536 ++++++++++++++++++ .../tachiyomi/ui/reader/ReaderMenu.java | 421 -------------- .../tachiyomi/ui/reader/ReaderPopupMenu.kt | 108 ++++ .../preference/LoginDialogPreference.kt | 2 +- app/src/main/res/layout/reader_menu.xml | 6 +- build.gradle | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- 14 files changed, 676 insertions(+), 854 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleAnimationListener.kt create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleSeekBarListener.kt rename app/src/main/java/eu/kanade/tachiyomi/{widget => ui/base/listener}/SimpleTextWatcher.kt (88%) delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt delete mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPopupMenu.kt diff --git a/app/build.gradle b/app/build.gradle index 21733f28f8..8a7fa86733 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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" diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 47deba4508..b3f505bc49 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -31,7 +31,8 @@ + android:parentActivityName=".ui.manga.MangaActivity" + android:theme="@style/Theme.Reader"> diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleAnimationListener.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleAnimationListener.kt new file mode 100644 index 0000000000..cb877b2bbf --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleAnimationListener.kt @@ -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) {} +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleSeekBarListener.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleSeekBarListener.kt new file mode 100644 index 0000000000..7d8bb3fceb --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleSeekBarListener.kt @@ -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) {} +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleTextWatcher.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleTextWatcher.kt similarity index 88% rename from app/src/main/java/eu/kanade/tachiyomi/widget/SimpleTextWatcher.kt rename to app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleTextWatcher.kt index ee39d58719..f88f5299af 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleTextWatcher.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/listener/SimpleTextWatcher.kt @@ -1,4 +1,4 @@ -package eu.kanade.tachiyomi.widget +package eu.kanade.tachiyomi.ui.base.listener import android.text.Editable import android.text.TextWatcher diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/myanimelist/MyAnimeListDialogFragment.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/myanimelist/MyAnimeListDialogFragment.kt index 1ac704282b..5110043b75 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/myanimelist/MyAnimeListDialogFragment.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/myanimelist/MyAnimeListDialogFragment.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java deleted file mode 100644 index 3f3e652f15..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.java +++ /dev/null @@ -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 { - - @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 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; - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt new file mode 100644 index 0000000000..cd65ec4941 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -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() { + + 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) + } + +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java deleted file mode 100644 index 443f931b2e..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderMenu.java +++ /dev/null @@ -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) { - - } - } - -} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPopupMenu.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPopupMenu.kt new file mode 100644 index 0000000000..579823b385 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderPopupMenu.kt @@ -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) + } + +} \ No newline at end of file diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt index 7fa2473496..1d850a61ca 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/preference/LoginDialogPreference.kt @@ -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 diff --git a/app/src/main/res/layout/reader_menu.xml b/app/src/main/res/layout/reader_menu.xml index 4d7f4166d4..e5c11ebc3c 100644 --- a/app/src/main/res/layout/reader_menu.xml +++ b/app/src/main/res/layout/reader_menu.xml @@ -29,7 +29,7 @@ android:layout_height="?attr/actionBarSize">