From 0af41005f8e4e3ccd454ebfa4a143b829a3f5dc2 Mon Sep 17 00:00:00 2001 From: Jay Date: Fri, 17 Apr 2020 00:04:44 -0400 Subject: [PATCH] Adding webtoon side margins + continuous vertical Co-Authored-By: arkon Co-Authored-By: morcefaster <51055657+morcefaster@users.noreply.github.com> --- .../data/preference/PreferenceKeys.kt | 2 + .../data/preference/PreferencesHelper.kt | 2 + .../tachiyomi/ui/reader/ReaderActivity.kt | 2 + .../ui/reader/ReaderSettingsSheet.kt | 19 ++++++- .../reader/viewer/webtoon/WebtoonAdapter.kt | 12 +++-- .../ui/reader/viewer/webtoon/WebtoonConfig.kt | 6 +++ .../viewer/webtoon/WebtoonPageHolder.kt | 14 +++++ .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 54 ++++++++++++++++--- .../ui/setting/SettingsReaderController.kt | 4 +- .../main/res/layout/reader_settings_sheet.xml | 45 ++++++++++++---- app/src/main/res/values/arrays.xml | 18 ++++++- app/src/main/res/values/strings.xml | 7 +++ 12 files changed, 158 insertions(+), 27 deletions(-) diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index 87364767b0..c510b9c110 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -51,6 +51,8 @@ object PreferenceKeys { const val readWithVolumeKeysInverted = "reader_volume_keys_inverted" + const val webtoonSidePadding = "webtoon_side_padding" + const val updateOnlyNonCompleted = "pref_update_only_non_completed_key" const val autoUpdateTrack = "pref_auto_update_manga_sync_key" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 9d133a9917..949b4846ed 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -95,6 +95,8 @@ class PreferencesHelper(val context: Context) { fun cropBordersWebtoon() = rxPrefs.getBoolean(Keys.cropBordersWebtoon, false) + fun webtoonSidePadding() = rxPrefs.getInteger(Keys.webtoonSidePadding, 0) + fun readWithTapping() = rxPrefs.getBoolean(Keys.readWithTapping, true) fun readWithLongTap() = rxPrefs.getBoolean(Keys.readWithLongTap, true) 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 index 040a491272..7cbefcf610 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt @@ -144,6 +144,7 @@ class ReaderActivity : BaseRxActivity(), const val RIGHT_TO_LEFT = 2 const val VERTICAL = 3 const val WEBTOON = 4 + const val VERTICAL_PLUS = 5 fun newIntent(context: Context, manga: Manga, chapter: Chapter): Intent { @@ -402,6 +403,7 @@ class ReaderActivity : BaseRxActivity(), RIGHT_TO_LEFT -> R2LPagerViewer(this) VERTICAL -> VerticalPagerViewer(this) WEBTOON -> WebtoonViewer(this) + VERTICAL_PLUS -> WebtoonViewer(this, isContinuous = false) else -> L2RPagerViewer(this) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt index 467760a918..2f109615c1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderSettingsSheet.kt @@ -8,6 +8,7 @@ import android.view.View import android.view.ViewGroup import android.widget.CompoundButton import android.widget.Spinner +import androidx.annotation.ArrayRes import com.f2prateek.rx.preferences.Preference import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetDialog @@ -55,7 +56,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : .getOrDefault() == 0 && activity.window.decorView.rootWindowInsets.systemWindowInsetRight == 0 && activity.window.decorView.rootWindowInsets.systemWindowInsetLeft == 0 ) window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR val height = activity.window.decorView.rootWindowInsets.systemWindowInsetBottom - sheetBehavior.peekHeight = 500.dpToPx + height + sheetBehavior.peekHeight = 550.dpToPx + height sheetBehavior.addBottomSheetCallback(object : BottomSheetBehavior.BottomSheetCallback() { override fun onSlide(bottomSheet: View, progress: Float) { @@ -87,7 +88,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : } setBottomEdge( - if (activity.viewer is PagerViewer) page_transitions else crop_borders_webtoon, activity + if (activity.viewer is PagerViewer) page_transitions else webtoon_side_padding, activity ) close_button.setOnClickListener { @@ -138,6 +139,7 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : webtoon_prefs_group.visible() pager_prefs_group.gone() crop_borders_webtoon.bindToPreference(preferences.cropBordersWebtoon()) + webtoon_side_padding.bindToIntPreference(preferences.webtoonSidePadding(), R.array.webtoon_side_padding_values) } /** @@ -162,4 +164,17 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : } setSelection(pref.getOrDefault() - offset, false) } + + /** + * Binds a spinner to an int preference. The position of the spinner item must + * correlate with the [intValues] resource item (in arrays.xml), which is a + * of int values that will be parsed here and applied to the preference. + */ + private fun Spinner.bindToIntPreference(pref: Preference, @ArrayRes intValuesResource: Int) { + val intValues = resources.getStringArray(intValuesResource).map { it.toIntOrNull() } + onItemSelectedListener = IgnoreFirstSpinnerListener { position -> + pref.set(intValues[position]) + } + setSelection(intValues.indexOf(pref.getOrDefault()), false) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt index d2897edf3e..409d9c71f1 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonAdapter.kt @@ -4,6 +4,7 @@ import android.view.ViewGroup import android.widget.FrameLayout import android.widget.LinearLayout import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.RecyclerView import eu.kanade.tachiyomi.ui.reader.model.ChapterTransition import eu.kanade.tachiyomi.ui.reader.model.ReaderChapter import eu.kanade.tachiyomi.ui.reader.model.ReaderPage @@ -12,7 +13,7 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters /** * RecyclerView Adapter used by this [viewer] to where [ViewerChapters] updates are posted. */ -class WebtoonAdapter(val viewer: WebtoonViewer) : androidx.recyclerview.widget.RecyclerView.Adapter() { +class WebtoonAdapter(val viewer: WebtoonViewer) : RecyclerView.Adapter() { /** * List of currently set items. @@ -20,6 +21,7 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : androidx.recyclerview.widget.R var items: List = emptyList() private set + var currentChapter: ReaderChapter? = null /** * Updates this adapter with the given [chapters]. It handles setting a few pages of the * next/previous chapter to allow seamless transitions. @@ -48,6 +50,8 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : androidx.recyclerview.widget.R newItems.addAll(currPages) } + currentChapter = chapters.currChapter + // Add next chapter transition and pages. if (forceTransition || chapters.nextChapter?.state !is ReaderChapter.State.Loaded) { newItems.add(ChapterTransition.Next(chapters.currChapter, chapters.nextChapter)) @@ -89,7 +93,7 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : androidx.recyclerview.widget.R /** * Creates a new view holder for an item with the given [viewType]. */ - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): androidx.recyclerview.widget.RecyclerView.ViewHolder { + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder { return when (viewType) { PAGE_VIEW -> { val view = FrameLayout(parent.context) @@ -106,7 +110,7 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : androidx.recyclerview.widget.R /** * Binds an existing view [holder] with the item at the given [position]. */ - override fun onBindViewHolder(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder, position: Int) { + override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) { val item = items[position] when (holder) { is WebtoonPageHolder -> holder.bind(item as ReaderPage) @@ -117,7 +121,7 @@ class WebtoonAdapter(val viewer: WebtoonViewer) : androidx.recyclerview.widget.R /** * Recycles an existing view [holder] before adding it to the view pool. */ - override fun onViewRecycled(holder: androidx.recyclerview.widget.RecyclerView.ViewHolder) { + override fun onViewRecycled(holder: RecyclerView.ViewHolder) { when (holder) { is WebtoonPageHolder -> holder.recycle() is WebtoonTransitionHolder -> holder.recycle() diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index f467047e4c..1c8dc66f03 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -37,6 +37,9 @@ class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) { var alwaysShowChapterTransition = true private set + var sidePadding = 0 + private set + init { preferences.readWithTapping() .register({ tappingEnabled = it }) @@ -58,6 +61,9 @@ class WebtoonConfig(preferences: PreferencesHelper = Injekt.get()) { preferences.alwaysShowChapterTransition() .register({ alwaysShowChapterTransition = it }) + + preferences.webtoonSidePadding() + .register({ sidePadding = it }, { imagePropertyChangedListener?.invoke() }) } fun unsubscribe() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt index 5187566b12..9791798dac 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonPageHolder.kt @@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.ui.reader.viewer.webtoon import android.annotation.SuppressLint import android.content.Intent +import android.content.res.Resources import android.graphics.drawable.Drawable import android.net.Uri import android.view.Gravity @@ -120,6 +121,19 @@ class WebtoonPageHolder( fun bind(page: ReaderPage) { this.page = page observeStatus() + refreshLayoutParams() + } + + private fun refreshLayoutParams() { + frame.layoutParams = FrameLayout.LayoutParams(MATCH_PARENT, WRAP_CONTENT).apply { + if (!viewer.isContinuous) { + bottomMargin = 15.dpToPx + } + + val margin = Resources.getSystem().displayMetrics.widthPixels * (viewer.config.sidePadding / 100f) + marginEnd = margin.toInt() + marginStart = margin.toInt() + } } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index 8e962c2d0c..1c7fa5f42b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -14,11 +14,13 @@ import eu.kanade.tachiyomi.ui.reader.model.ViewerChapters import eu.kanade.tachiyomi.ui.reader.viewer.BaseViewer import rx.subscriptions.CompositeSubscription import timber.log.Timber +import kotlin.math.max +import kotlin.math.min /** * Implementation of a [BaseViewer] to display pages with a [RecyclerView]. */ -class WebtoonViewer(val activity: ReaderActivity) : BaseViewer { +class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = true) : BaseViewer { /** * Recycler view used by this viewer. @@ -70,10 +72,11 @@ class WebtoonViewer(val activity: ReaderActivity) : BaseViewer { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { val position = layoutManager.findLastEndVisibleItemPosition() val item = adapter.items.getOrNull(position) + val allowPreload = checkAllowPreload(item as? ReaderPage) if (item != null && currentPage != item) { currentPage = item when (item) { - is ReaderPage -> onPageSelected(item, position) + is ReaderPage -> onPageSelected(item, allowPreload) is ChapterTransition -> onTransitionSelected(item) } } @@ -113,10 +116,34 @@ class WebtoonViewer(val activity: ReaderActivity) : BaseViewer { false } + config.imagePropertyChangedListener = { + refreshAdapter() + } + frame.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT) frame.addView(recycler) } + private fun checkAllowPreload(page: ReaderPage?): Boolean { + // Page is transition page - preload allowed + page == null ?: return true + + // Initial opening - preload allowed + currentPage == null ?: return true + + val nextItem = adapter.items.getOrNull(adapter.items.count() - 1) + val nextChapter = (nextItem as? ChapterTransition.Next)?.to ?: (nextItem as? ReaderPage)?.chapter + + // Allow preload for + // 1. Going between pages of same chapter + // 2. Next chapter page + return when (page!!.chapter) { + (currentPage as? ReaderPage)?.chapter -> true + nextChapter -> true + else -> false + } + } + /** * Returns the view this viewer uses. */ @@ -137,18 +164,20 @@ class WebtoonViewer(val activity: ReaderActivity) : BaseViewer { * Called from the RecyclerView listener when a [page] is marked as active. It notifies the * activity of the change and requests the preload of the next chapter if this is the last page. */ - private fun onPageSelected(page: ReaderPage, position: Int) { + private fun onPageSelected(page: ReaderPage, allowPreload: Boolean) { val pages = page.chapter.pages!! // Won't be null because it's the loaded chapter Timber.d("onPageSelected: ${page.number}/${pages.size}") activity.onPageSelected(page) // Preload next chapter once we're within the last 3 pages of the current chapter val inPreloadRange = pages.size - page.number < 3 - if (inPreloadRange) { + if (inPreloadRange && allowPreload && page.chapter == adapter.currentChapter) { Timber.d("Request preload next chapter because we're at page ${page.number} of ${pages.size}") - val transition = adapter.items.getOrNull(pages.size + 1) as? ChapterTransition.Next - if (transition?.to != null) { - activity.requestPreloadChapter(transition.to) + val nextItem = adapter.items.getOrNull(adapter.items.size - 1) + val transitionChapter = (nextItem as? ChapterTransition.Next)?.to ?: (nextItem as?ReaderPage)?.chapter + if (transitionChapter != null) { + Timber.d("Requesting to preload chapter ${transitionChapter.chapter.chapter_number}") + activity.requestPreloadChapter(transitionChapter) } } } @@ -255,4 +284,15 @@ class WebtoonViewer(val activity: ReaderActivity) : BaseViewer { override fun handleGenericMotionEvent(event: MotionEvent): Boolean { return false } + + /** + * Notifies adapter of changes around the current page to trigger a relayout in the recycler. + * Used when an image configuration is changed. + */ + private fun refreshAdapter() { + val position = layoutManager.findLastEndVisibleItemPosition() + adapter.notifyItemRangeChanged( + max(0, position - 2), + min(position + 2, adapter.itemCount - 1)) + } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index 416f7a75d8..901808033d 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -14,8 +14,8 @@ class SettingsReaderController : SettingsController() { key = Keys.defaultViewer titleRes = R.string.default_viewer entriesRes = arrayOf(R.string.left_to_right_viewer, R.string.right_to_left_viewer, - R.string.vertical_viewer, R.string.webtoon) - entryRange = 1..4 + R.string.vertical_viewer, R.string.webtoon, R.string.continuous_vertical) + entryRange = 1..5 defaultValue = 1 } intListPreference(activity) { diff --git a/app/src/main/res/layout/reader_settings_sheet.xml b/app/src/main/res/layout/reader_settings_sheet.xml index ff4c87e095..3c211e4df3 100644 --- a/app/src/main/res/layout/reader_settings_sheet.xml +++ b/app/src/main/res/layout/reader_settings_sheet.xml @@ -98,7 +98,7 @@ app:layout_constraintStart_toEndOf="@id/bottom_line" app:layout_constraintTop_toBottomOf="@id/rotation_mode" /> - - - - - - - - + + + + + app:constraint_referenced_ids="webtoon_prefs,crop_borders_webtoon, + webtoon_side_padding_text,webtoon_side_padding" /> @string/right_to_left_viewer @string/vertical_viewer @string/webtoon + @string/continuous_vertical @@ -25,6 +26,22 @@ @string/smart_fit + + @string/webtoon_side_padding_0 + @string/webtoon_side_padding_10 + @string/webtoon_side_padding_15 + @string/webtoon_side_padding_20 + @string/webtoon_side_padding_25 + + + + 0 + 10 + 15 + 20 + 25 + + @string/automatic @string/left @@ -44,5 +61,4 @@ @string/multiply @string/screen - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 9111bd7093..fcf046a6c2 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -291,6 +291,7 @@ Left to right Right to left Vertical + Continuous vertical Pager Scale type Fit screen @@ -309,6 +310,12 @@ Smart (based on page) Smart (based on page and theme) Always show chapter transition + Side padding + None + 10% + 15% + 20% + 25% About this %1$s