Option to prefer Rtl reader

This commit is contained in:
Koitharu
2020-11-02 19:13:07 +02:00
parent 72fdc7796f
commit e497781359
16 changed files with 113 additions and 86 deletions

View File

@@ -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'

View File

@@ -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)

View File

@@ -2,7 +2,6 @@ package org.koitharu.kotatsu.core.prefs
enum class ReaderMode(val id: Int) {
UNKNOWN(0),
STANDARD(1),
WEBTOON(2),
REVERSED(3);

View File

@@ -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<MangaPage>): ReaderMode? {
suspend fun determineMangaIsWebtoon(pages: List<MangaPage>): 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()

View File

@@ -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<ImageLoader>()
fun stringArg(name: String) = StringArgumentDelegate(name)
@Deprecated("Use extension", replaceWith = ReplaceWith("parcelableArgument(name)"))
fun <T : Parcelable> arg(name: String) = ParcelableArgumentDelegate<T>(name)
open fun getTitle(): CharSequence? = null
override fun onAttach(context: Context) {

View File

@@ -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) {

View File

@@ -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
}

View File

@@ -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<ReaderView>() {
private val dataRepository by inject<MangaDataRepository>()
private val appSettings by inject<AppSettings>()
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<ReaderView>() {
}
}
private fun getReaderMode(isWebtoon: Boolean?) = when {
isWebtoon == true -> ReaderMode.WEBTOON
appSettings.isPreferRtlReader -> ReaderMode.REVERSED
else -> ReaderMode.STANDARD
}
companion object : KoinComponent {
fun saveState(state: ReaderState) {

View File

@@ -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<Unit>() {
private val presenter by moxyPresenter(factory = ::SearchPresenter)
private val query by stringArg(ARG_QUERY)
private val source by arg<MangaSource>(ARG_SOURCE)
private val query by stringArgument(ARG_QUERY)
private val source by parcelableArgument<MangaSource>(ARG_SOURCE)
override fun onRequestMoreItems(offset: Int) {
presenter.loadList(source, query.orEmpty(), offset)

View File

@@ -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<Unit>() {
class GlobalSearchFragment : MangaListFragment<Unit>() {
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) {

View File

@@ -20,4 +20,9 @@ inline fun <T : Parcelable> Fragment.parcelableArgument(name: String) =
lazy<T>(LazyThreadSafetyMode.NONE) {
requireArguments().getParcelable(name)
?: error("No argument $name passed in ${javaClass.simpleName}")
}
}
@Suppress("NOTHING_TO_INLINE")
inline fun Fragment.stringArgument(name: String) = lazy(LazyThreadSafetyMode.NONE) {
arguments?.getString(name)
}

View File

@@ -160,4 +160,6 @@
<string name="update_check_failed">Ошибка при проверке обновления</string>
<string name="no_update_available">Нет доступных обновлений</string>
<string name="right_to_left">Справа налево</string>
<string name="prefer_rtl_reader">Предпочитать режим Справа налево</string>
<string name="prefer_rtl_reader_summary">Вы можете настроить режим чтения для каждой манги отдельно</string>
</resources>

View File

@@ -23,6 +23,7 @@
<string name="key_notifications_vibrate">notifications_vibrate</string>
<string name="key_notifications_light">notifications_light</string>
<string name="key_reader_animation">reader_animation</string>
<string name="key_reader_prefer_rtl">reader_prefer_rtl</string>
<string name="key_app_password">app_password</string>
<string name="key_protect_app">protect_app</string>
<string name="key_app_version">app_version</string>

View File

@@ -161,4 +161,6 @@
<string name="update_check_failed">Update check failed</string>
<string name="no_update_available">No updates available</string>
<string name="right_to_left">Right to left</string>
<string name="prefer_rtl_reader">Prefer Right to left reader</string>
<string name="prefer_rtl_reader_summary">You can set up the reading mode for each manga separately</string>
</resources>

View File

@@ -70,6 +70,13 @@
android:title="@string/pages_animation"
app:iconSpaceReserved="false" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_reader_prefer_rtl"
android:summary="@string/prefer_rtl_reader_summary"
android:title="@string/prefer_rtl_reader"
app:iconSpaceReserved="false" />
<PreferenceCategory
android:title="@string/new_chapters"
app:allowDividerAbove="true"

View File

@@ -13,8 +13,15 @@
<SwitchPreferenceCompat
android:defaultValue="false"
android:title="@string/pages_animation"
android:key="@string/key_reader_animation"
android:title="@string/pages_animation"
app:iconSpaceReserved="false" />
<SwitchPreference
android:defaultValue="false"
android:key="@string/key_reader_prefer_rtl"
android:summary="@string/prefer_rtl_reader_summary"
android:title="@string/prefer_rtl_reader"
app:iconSpaceReserved="false" />
</PreferenceScreen>