From e497781359fb217da6f0c20603be287918549a4a Mon Sep 17 00:00:00 2001 From: Koitharu Date: Mon, 2 Nov 2020 19:13:07 +0200 Subject: [PATCH] Option to prefer Rtl reader --- app/build.gradle | 2 +- .../kotatsu/core/prefs/AppSettings.kt | 5 + .../koitharu/kotatsu/core/prefs/ReaderMode.kt | 1 - .../org/koitharu/kotatsu/domain/MangaUtils.kt | 8 +- .../koitharu/kotatsu/ui/base/BaseFragment.kt | 8 -- .../kotatsu/ui/reader/ReaderActivity.kt | 116 +++++++++--------- .../kotatsu/ui/reader/ReaderConfigDialog.kt | 3 +- .../kotatsu/ui/reader/ReaderPresenter.kt | 17 ++- .../kotatsu/ui/search/SearchFragment.kt | 6 +- .../ui/search/global/GlobalSearchFragment.kt | 5 +- .../koitharu/kotatsu/utils/ext/FragmentExt.kt | 7 +- app/src/main/res/values-ru/strings.xml | 2 + app/src/main/res/values/constants.xml | 1 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/pref_main.xml | 7 ++ app/src/main/res/xml/pref_reader.xml | 9 +- 16 files changed, 113 insertions(+), 86 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 788959cbb..4a94d66b2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -70,7 +70,7 @@ dependencies { implementation 'androidx.activity:activity-ktx:1.2.0-beta01' implementation 'androidx.fragment:fragment-ktx:1.3.0-beta01' implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.3.0-beta01' - implementation 'androidx.constraintlayout:constraintlayout:2.0.2' + implementation 'androidx.constraintlayout:constraintlayout:2.0.4' implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.1.0' implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha06' implementation 'androidx.viewpager2:viewpager2:1.1.0-alpha01' diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt index e19d5394a..b7c6d3d35 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/AppSettings.kt @@ -88,6 +88,11 @@ class AppSettings private constructor(resources: Resources, private val prefs: S false ) + val isPreferRtlReader by BoolPreferenceDelegate( + resources.getString(R.string.key_reader_prefer_rtl), + false + ) + val trackSources by StringSetPreferenceDelegate( resources.getString(R.string.key_track_sources), arraySetOf(TRACK_FAVOURITES, TRACK_HISTORY) diff --git a/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt b/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt index 89fa40761..9ec51d479 100644 --- a/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt +++ b/app/src/main/java/org/koitharu/kotatsu/core/prefs/ReaderMode.kt @@ -2,7 +2,6 @@ package org.koitharu.kotatsu.core.prefs enum class ReaderMode(val id: Int) { - UNKNOWN(0), STANDARD(1), WEBTOON(2), REVERSED(3); diff --git a/app/src/main/java/org/koitharu/kotatsu/domain/MangaUtils.kt b/app/src/main/java/org/koitharu/kotatsu/domain/MangaUtils.kt index 157efe9f6..cf581dc41 100644 --- a/app/src/main/java/org/koitharu/kotatsu/domain/MangaUtils.kt +++ b/app/src/main/java/org/koitharu/kotatsu/domain/MangaUtils.kt @@ -10,7 +10,6 @@ import org.koin.core.component.KoinComponent import org.koin.core.component.get import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.model.MangaPage -import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.utils.ext.await import org.koitharu.kotatsu.utils.ext.medianOrNull import java.io.InputStream @@ -24,7 +23,7 @@ object MangaUtils : KoinComponent { */ @WorkerThread @Suppress("BlockingMethodInNonBlockingContext") - suspend fun determineReaderMode(pages: List): ReaderMode? { + suspend fun determineMangaIsWebtoon(pages: List): Boolean? { try { val page = pages.medianOrNull() ?: return null val url = page.source.repository.getPageFullUrl(page) @@ -45,10 +44,7 @@ object MangaUtils : KoinComponent { getBitmapSize(it.body?.byteStream()) } } - return when { - size.width * 2 < size.height -> ReaderMode.WEBTOON - else -> ReaderMode.STANDARD - } + return size.width * 2 < size.height } catch (e: Exception) { if (BuildConfig.DEBUG) { e.printStackTrace() diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/base/BaseFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/base/BaseFragment.kt index 0b94bca26..9ca17d71f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/base/BaseFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/base/BaseFragment.kt @@ -1,13 +1,10 @@ package org.koitharu.kotatsu.ui.base import android.content.Context -import android.os.Parcelable import androidx.annotation.LayoutRes import coil.ImageLoader import moxy.MvpAppCompatFragment import org.koin.android.ext.android.inject -import org.koitharu.kotatsu.utils.delegates.ParcelableArgumentDelegate -import org.koitharu.kotatsu.utils.delegates.StringArgumentDelegate abstract class BaseFragment( @LayoutRes contentLayoutId: Int @@ -15,11 +12,6 @@ abstract class BaseFragment( protected val coil by inject() - fun stringArg(name: String) = StringArgumentDelegate(name) - - @Deprecated("Use extension", replaceWith = ReplaceWith("parcelableArgument(name)")) - fun arg(name: String) = ParcelableArgumentDelegate(name) - open fun getTitle(): CharSequence? = null override fun onAttach(context: Context) { diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt index d4b9c0a15..57dd7cd44 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderActivity.kt @@ -125,7 +125,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh replace(R.id.container, ReversedReaderFragment.newInstance(state)) } } - else -> if (currentReader !is PagerReaderFragment) { + ReaderMode.STANDARD -> if (currentReader !is PagerReaderFragment) { supportFragmentManager.commit { replace(R.id.container, PagerReaderFragment.newInstance(state)) } @@ -135,7 +135,7 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh when (mode) { ReaderMode.WEBTOON -> R.drawable.ic_script ReaderMode.REVERSED -> R.drawable.ic_read_reversed - else -> R.drawable.ic_book_page + ReaderMode.STANDARD -> R.drawable.ic_book_page } ) appbar_top.postDelayed(1000) { @@ -158,70 +158,70 @@ class ReaderActivity : BaseFullscreenActivity(), ReaderView, ChaptersDialog.OnCh outState.putParcelable(EXTRA_STATE, state) } - override fun onOptionsItemSelected(item: MenuItem) = when (item.itemId) { - R.id.action_reader_mode -> { - ReaderConfigDialog.show( - supportFragmentManager, when (reader) { - is PagerReaderFragment -> ReaderMode.STANDARD - is WebtoonReaderFragment -> ReaderMode.WEBTOON - is ReversedReaderFragment -> ReaderMode.REVERSED - else -> ReaderMode.UNKNOWN - } - ) - true - } - R.id.action_settings -> { - startActivity(SimpleSettingsActivity.newReaderSettingsIntent(this)) - true - } - R.id.action_chapters -> { - ChaptersDialog.show( - supportFragmentManager, - state.manga.chapters.orEmpty(), - state.chapterId - ) - true - } - R.id.action_screen_rotate -> { - orientationHelper.toggleOrientation() - true - } - R.id.action_pages_thumbs -> { - if (reader?.hasItems == true) { - val pages = reader?.getPages() - if (!pages.isNullOrEmpty()) { - PagesThumbnailsSheet.show( - supportFragmentManager, pages, - state.chapter?.name ?: title?.toString().orEmpty() - ) + override fun onOptionsItemSelected(item: MenuItem): Boolean { + when (item.itemId) { + R.id.action_reader_mode -> { + ReaderConfigDialog.show( + supportFragmentManager, when (reader) { + is PagerReaderFragment -> ReaderMode.STANDARD + is WebtoonReaderFragment -> ReaderMode.WEBTOON + is ReversedReaderFragment -> ReaderMode.REVERSED + else -> { + showWaitWhileLoading() + return false + } + } + ) + } + R.id.action_settings -> { + startActivity(SimpleSettingsActivity.newReaderSettingsIntent(this)) + } + R.id.action_chapters -> { + ChaptersDialog.show( + supportFragmentManager, + state.manga.chapters.orEmpty(), + state.chapterId + ) + } + R.id.action_screen_rotate -> { + orientationHelper.toggleOrientation() + } + R.id.action_pages_thumbs -> { + if (reader?.hasItems == true) { + val pages = reader?.getPages() + if (!pages.isNullOrEmpty()) { + PagesThumbnailsSheet.show( + supportFragmentManager, pages, + state.chapter?.name ?: title?.toString().orEmpty() + ) + } else { + showWaitWhileLoading() + } } else { showWaitWhileLoading() } - } else { - showWaitWhileLoading() } - true - } - R.id.action_save_page -> { - if (reader?.hasItems == true) { - if (ContextCompat.checkSelfPermission( - this, - Manifest.permission.WRITE_EXTERNAL_STORAGE - ) == PackageManager.PERMISSION_GRANTED - ) { - onActivityResult(true) + R.id.action_save_page -> { + if (reader?.hasItems == true) { + if (ContextCompat.checkSelfPermission( + this, + Manifest.permission.WRITE_EXTERNAL_STORAGE + ) == PackageManager.PERMISSION_GRANTED + ) { + onActivityResult(true) + } else { + registerForActivityResult( + ActivityResultContracts.RequestPermission(), + this + ).launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + } } else { - registerForActivityResult( - ActivityResultContracts.RequestPermission(), - this - ).launch(Manifest.permission.WRITE_EXTERNAL_STORAGE) + showWaitWhileLoading() } - } else { - showWaitWhileLoading() } - true + else -> return super.onOptionsItemSelected(item) } - else -> super.onOptionsItemSelected(item) + return true } override fun onActivityResult(result: Boolean) { diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderConfigDialog.kt b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderConfigDialog.kt index 791fed5d3..d0c9f4265 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderConfigDialog.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderConfigDialog.kt @@ -18,9 +18,8 @@ class ReaderConfigDialog : AlertDialogFragment(R.layout.dialog_reader_config), override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - mode = arguments?.getInt(ARG_MODE, ReaderMode.UNKNOWN.id) + mode = arguments?.getInt(ARG_MODE) ?.let { ReaderMode.valueOf(it) } - ?.takeUnless { it == ReaderMode.UNKNOWN } ?: ReaderMode.STANDARD } diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt index da4424ea3..ebb9a8290 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/reader/ReaderPresenter.kt @@ -13,6 +13,7 @@ import org.koin.core.component.inject import org.koitharu.kotatsu.BuildConfig import org.koitharu.kotatsu.core.model.Manga import org.koitharu.kotatsu.core.model.MangaPage +import org.koitharu.kotatsu.core.prefs.AppSettings import org.koitharu.kotatsu.core.prefs.ReaderMode import org.koitharu.kotatsu.domain.MangaDataRepository import org.koitharu.kotatsu.domain.MangaUtils @@ -28,27 +29,29 @@ import org.koitharu.kotatsu.utils.ext.mimeType class ReaderPresenter : BasePresenter() { private val dataRepository by inject() + private val appSettings by inject() fun init(manga: Manga) { presenterScope.launch { viewState.onLoadingStateChanged(isLoading = true) try { - val mode = withContext(Dispatchers.IO) { + val mode = withContext(Dispatchers.Default) { val repo = manga.source.repository val chapter = (manga.chapters ?: throw RuntimeException("Chapters is null")).random() var mode = dataRepository.getReaderMode(manga.id) if (mode == null) { val pages = repo.getPages(chapter) - mode = MangaUtils.determineReaderMode(pages) - if (mode != null) { + val isWebtoon = MangaUtils.determineMangaIsWebtoon(pages) + mode = getReaderMode(isWebtoon) + if (isWebtoon != null) { dataRepository.savePreferences( manga = manga, mode = mode ) } } - mode ?: ReaderMode.UNKNOWN + mode } viewState.onInitReader(manga, mode) } catch (_: CancellationException) { @@ -101,6 +104,12 @@ class ReaderPresenter : BasePresenter() { } } + private fun getReaderMode(isWebtoon: Boolean?) = when { + isWebtoon == true -> ReaderMode.WEBTOON + appSettings.isPreferRtlReader -> ReaderMode.REVERSED + else -> ReaderMode.STANDARD + } + companion object : KoinComponent { fun saveState(state: ReaderState) { diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt index 6487e4555..1a796624f 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/search/SearchFragment.kt @@ -3,14 +3,16 @@ package org.koitharu.kotatsu.ui.search import moxy.ktx.moxyPresenter import org.koitharu.kotatsu.core.model.MangaSource import org.koitharu.kotatsu.ui.list.MangaListFragment +import org.koitharu.kotatsu.utils.ext.parcelableArgument +import org.koitharu.kotatsu.utils.ext.stringArgument import org.koitharu.kotatsu.utils.ext.withArgs class SearchFragment : MangaListFragment() { private val presenter by moxyPresenter(factory = ::SearchPresenter) - private val query by stringArg(ARG_QUERY) - private val source by arg(ARG_SOURCE) + private val query by stringArgument(ARG_QUERY) + private val source by parcelableArgument(ARG_SOURCE) override fun onRequestMoreItems(offset: Int) { presenter.loadList(source, query.orEmpty(), offset) diff --git a/app/src/main/java/org/koitharu/kotatsu/ui/search/global/GlobalSearchFragment.kt b/app/src/main/java/org/koitharu/kotatsu/ui/search/global/GlobalSearchFragment.kt index 5a08335ba..bf05ceff3 100644 --- a/app/src/main/java/org/koitharu/kotatsu/ui/search/global/GlobalSearchFragment.kt +++ b/app/src/main/java/org/koitharu/kotatsu/ui/search/global/GlobalSearchFragment.kt @@ -2,14 +2,15 @@ package org.koitharu.kotatsu.ui.search.global import moxy.ktx.moxyPresenter import org.koitharu.kotatsu.ui.list.MangaListFragment +import org.koitharu.kotatsu.utils.ext.stringArgument import org.koitharu.kotatsu.utils.ext.withArgs -class GlobalSearchFragment: MangaListFragment() { +class GlobalSearchFragment : MangaListFragment() { private val presenter by moxyPresenter(factory = ::GlobalSearchPresenter) - private val query by stringArg(ARG_QUERY) + private val query by stringArgument(ARG_QUERY) override fun onRequestMoreItems(offset: Int) { if (offset == 0) { diff --git a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt index 2297333cc..9cea220ad 100644 --- a/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt +++ b/app/src/main/java/org/koitharu/kotatsu/utils/ext/FragmentExt.kt @@ -20,4 +20,9 @@ inline fun Fragment.parcelableArgument(name: String) = lazy(LazyThreadSafetyMode.NONE) { requireArguments().getParcelable(name) ?: error("No argument $name passed in ${javaClass.simpleName}") - } \ No newline at end of file + } + +@Suppress("NOTHING_TO_INLINE") +inline fun Fragment.stringArgument(name: String) = lazy(LazyThreadSafetyMode.NONE) { + arguments?.getString(name) +} \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 0656a7eae..2cfc33a41 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -160,4 +160,6 @@ Ошибка при проверке обновления Нет доступных обновлений Справа налево + Предпочитать режим Справа налево + Вы можете настроить режим чтения для каждой манги отдельно \ No newline at end of file diff --git a/app/src/main/res/values/constants.xml b/app/src/main/res/values/constants.xml index da5d6debf..0d53384e0 100644 --- a/app/src/main/res/values/constants.xml +++ b/app/src/main/res/values/constants.xml @@ -23,6 +23,7 @@ notifications_vibrate notifications_light reader_animation + reader_prefer_rtl app_password protect_app app_version diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 7ad520686..e30893499 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -161,4 +161,6 @@ Update check failed No updates available Right to left + Prefer Right to left reader + You can set up the reading mode for each manga separately \ No newline at end of file diff --git a/app/src/main/res/xml/pref_main.xml b/app/src/main/res/xml/pref_main.xml index 65c71dedc..a1ccf238b 100644 --- a/app/src/main/res/xml/pref_main.xml +++ b/app/src/main/res/xml/pref_main.xml @@ -70,6 +70,13 @@ android:title="@string/pages_animation" app:iconSpaceReserved="false" /> + + + + \ No newline at end of file