Let users invert dual page split (#4470)
* Let users invert dual page split * Use Activity lifecycleScope and cleanup invert logic
This commit is contained in:
parent
3a790f3d66
commit
776610d0e6
@ -25,6 +25,8 @@ object PreferenceKeys {
|
|||||||
|
|
||||||
const val dualPageSplit = "pref_dual_page_split"
|
const val dualPageSplit = "pref_dual_page_split"
|
||||||
|
|
||||||
|
const val dualPageInvert = "pref_dual_page_invert"
|
||||||
|
|
||||||
const val showReadingMode = "pref_show_reading_mode"
|
const val showReadingMode = "pref_show_reading_mode"
|
||||||
|
|
||||||
const val trueColor = "pref_true_color_key"
|
const val trueColor = "pref_true_color_key"
|
||||||
|
@ -91,6 +91,8 @@ class PreferencesHelper(val context: Context) {
|
|||||||
|
|
||||||
fun dualPageSplit() = flowPrefs.getBoolean(Keys.dualPageSplit, false)
|
fun dualPageSplit() = flowPrefs.getBoolean(Keys.dualPageSplit, false)
|
||||||
|
|
||||||
|
fun dualPageInvert() = flowPrefs.getBoolean(Keys.dualPageInvert, false)
|
||||||
|
|
||||||
fun showReadingMode() = prefs.getBoolean(Keys.showReadingMode, true)
|
fun showReadingMode() = prefs.getBoolean(Keys.showReadingMode, true)
|
||||||
|
|
||||||
fun trueColor() = flowPrefs.getBoolean(Keys.trueColor, false)
|
fun trueColor() = flowPrefs.getBoolean(Keys.trueColor, false)
|
||||||
|
@ -6,14 +6,17 @@ import android.widget.Spinner
|
|||||||
import androidx.annotation.ArrayRes
|
import androidx.annotation.ArrayRes
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
import androidx.core.widget.NestedScrollView
|
import androidx.core.widget.NestedScrollView
|
||||||
|
import androidx.lifecycle.lifecycleScope
|
||||||
import com.tfcporciuncula.flow.Preference
|
import com.tfcporciuncula.flow.Preference
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
import eu.kanade.tachiyomi.data.preference.PreferencesHelper
|
||||||
|
import eu.kanade.tachiyomi.data.preference.asImmediateFlow
|
||||||
import eu.kanade.tachiyomi.databinding.ReaderSettingsSheetBinding
|
import eu.kanade.tachiyomi.databinding.ReaderSettingsSheetBinding
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
|
import eu.kanade.tachiyomi.ui.reader.viewer.pager.PagerViewer
|
||||||
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
import eu.kanade.tachiyomi.ui.reader.viewer.webtoon.WebtoonViewer
|
||||||
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
import eu.kanade.tachiyomi.widget.IgnoreFirstSpinnerListener
|
||||||
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
import eu.kanade.tachiyomi.widget.sheet.BaseBottomSheetDialog
|
||||||
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -71,6 +74,12 @@ class ReaderSettingsSheet(private val activity: ReaderActivity) : BaseBottomShee
|
|||||||
binding.alwaysShowChapterTransition.bindToPreference(preferences.alwaysShowChapterTransition())
|
binding.alwaysShowChapterTransition.bindToPreference(preferences.alwaysShowChapterTransition())
|
||||||
binding.pageTransitions.bindToPreference(preferences.pageTransitions())
|
binding.pageTransitions.bindToPreference(preferences.pageTransitions())
|
||||||
|
|
||||||
|
// Makes so that dual page invert gets hidden away when turning of dual page split
|
||||||
|
preferences.dualPageSplit()
|
||||||
|
.asImmediateFlow { binding.dualPageInvert.isVisible = it }
|
||||||
|
.launchIn(activity.lifecycleScope)
|
||||||
|
binding.dualPageInvert.bindToPreference(preferences.dualPageInvert())
|
||||||
|
|
||||||
// If the preference is explicitly disabled, that means the setting was configured since there is a cutout
|
// If the preference is explicitly disabled, that means the setting was configured since there is a cutout
|
||||||
if (activity.hasCutout || !preferences.cutoutShort().get()) {
|
if (activity.hasCutout || !preferences.cutoutShort().get()) {
|
||||||
binding.cutoutShort.isVisible = true
|
binding.cutoutShort.isVisible = true
|
||||||
|
@ -25,6 +25,7 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
|
|||||||
var trueColor = false
|
var trueColor = false
|
||||||
var alwaysShowChapterTransition = true
|
var alwaysShowChapterTransition = true
|
||||||
var dualPageSplit = false
|
var dualPageSplit = false
|
||||||
|
var dualPageInvert = false
|
||||||
var navigationMode = 0
|
var navigationMode = 0
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
@ -58,6 +59,9 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
|
|||||||
|
|
||||||
preferences.dualPageSplit()
|
preferences.dualPageSplit()
|
||||||
.register({ dualPageSplit = it }, { imagePropertyChangedListener?.invoke() })
|
.register({ dualPageSplit = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
|
||||||
|
preferences.dualPageInvert()
|
||||||
|
.register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract fun defaultNavigation(): ViewerNavigation
|
protected abstract fun defaultNavigation(): ViewerNavigation
|
||||||
|
@ -264,24 +264,29 @@ class PagerPageHolder(
|
|||||||
else -> ImageUtil.isDoublePage(inputStream)
|
else -> ImageUtil.isDoublePage(inputStream)
|
||||||
}
|
}
|
||||||
inputStream = stream
|
inputStream = stream
|
||||||
if (isDoublePage) {
|
|
||||||
val side = when {
|
|
||||||
viewer is L2RPagerViewer && page is InsertPage -> ImageUtil.Side.RIGHT
|
|
||||||
viewer is R2LPagerViewer && page is InsertPage -> ImageUtil.Side.LEFT
|
|
||||||
viewer is L2RPagerViewer && page !is InsertPage -> ImageUtil.Side.LEFT
|
|
||||||
viewer is R2LPagerViewer && page !is InsertPage -> ImageUtil.Side.RIGHT
|
|
||||||
viewer is VerticalPagerViewer && page !is InsertPage -> ImageUtil.Side.RIGHT
|
|
||||||
viewer is VerticalPagerViewer && page is InsertPage -> ImageUtil.Side.LEFT
|
|
||||||
else -> error("We should choose a side!")
|
|
||||||
}
|
|
||||||
|
|
||||||
if (page !is InsertPage) {
|
if (!isDoublePage) return inputStream
|
||||||
onPageSplit()
|
|
||||||
}
|
|
||||||
|
|
||||||
inputStream = ImageUtil.splitInHalf(inputStream, side)
|
var side = when {
|
||||||
|
viewer is L2RPagerViewer && page is InsertPage -> ImageUtil.Side.RIGHT
|
||||||
|
(viewer is R2LPagerViewer || viewer is VerticalPagerViewer) && page is InsertPage -> ImageUtil.Side.LEFT
|
||||||
|
viewer is L2RPagerViewer && page !is InsertPage -> ImageUtil.Side.LEFT
|
||||||
|
(viewer is R2LPagerViewer || viewer is VerticalPagerViewer) && page !is InsertPage -> ImageUtil.Side.RIGHT
|
||||||
|
else -> error("We should choose a side!")
|
||||||
}
|
}
|
||||||
return inputStream
|
|
||||||
|
if (viewer.config.dualPageInvert) {
|
||||||
|
side = when (side) {
|
||||||
|
ImageUtil.Side.RIGHT -> ImageUtil.Side.LEFT
|
||||||
|
ImageUtil.Side.LEFT -> ImageUtil.Side.RIGHT
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page !is InsertPage) {
|
||||||
|
onPageSplit()
|
||||||
|
}
|
||||||
|
|
||||||
|
return ImageUtil.splitInHalf(inputStream, side)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onPageSplit() {
|
private fun onPageSplit() {
|
||||||
|
@ -292,7 +292,8 @@ class WebtoonPageHolder(
|
|||||||
openStream = if (!isDoublePage) {
|
openStream = if (!isDoublePage) {
|
||||||
stream
|
stream
|
||||||
} else {
|
} else {
|
||||||
ImageUtil.splitAndMerge(stream)
|
val upperSide = if (viewer.config.dualPageInvert) ImageUtil.Side.LEFT else ImageUtil.Side.RIGHT
|
||||||
|
ImageUtil.splitAndMerge(stream, upperSide)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isAnimated) {
|
if (!isAnimated) {
|
||||||
|
@ -55,6 +55,13 @@ class SettingsReaderController : SettingsController() {
|
|||||||
titleRes = R.string.pref_dual_page_split
|
titleRes = R.string.pref_dual_page_split
|
||||||
defaultValue = false
|
defaultValue = false
|
||||||
}
|
}
|
||||||
|
switchPreference {
|
||||||
|
key = Keys.dualPageInvert
|
||||||
|
titleRes = R.string.pref_dual_page_invert
|
||||||
|
summaryRes = R.string.pref_dual_page_invert_summary
|
||||||
|
defaultValue = false
|
||||||
|
preferences.dualPageSplit().asImmediateFlow { isVisible = it }.launchIn(viewScope)
|
||||||
|
}
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
switchPreference {
|
switchPreference {
|
||||||
key = Keys.trueColor
|
key = Keys.trueColor
|
||||||
|
@ -115,7 +115,7 @@ object ImageUtil {
|
|||||||
/**
|
/**
|
||||||
* Split the image into left and right parts, then merge them into a new image.
|
* Split the image into left and right parts, then merge them into a new image.
|
||||||
*/
|
*/
|
||||||
fun splitAndMerge(imageStream: InputStream): InputStream {
|
fun splitAndMerge(imageStream: InputStream, upperSide: Side): InputStream {
|
||||||
val imageBytes = imageStream.readBytes()
|
val imageBytes = imageStream.readBytes()
|
||||||
|
|
||||||
val imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
|
val imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
|
||||||
@ -125,11 +125,17 @@ object ImageUtil {
|
|||||||
val result = Bitmap.createBitmap(width / 2, height * 2, Bitmap.Config.ARGB_8888)
|
val result = Bitmap.createBitmap(width / 2, height * 2, Bitmap.Config.ARGB_8888)
|
||||||
val canvas = Canvas(result)
|
val canvas = Canvas(result)
|
||||||
// right -> upper
|
// right -> upper
|
||||||
val rightPart = Rect(width - width / 2, 0, width, height)
|
val rightPart = when (upperSide) {
|
||||||
|
Side.RIGHT -> Rect(width - width / 2, 0, width, height)
|
||||||
|
Side.LEFT -> Rect(0, 0, width / 2, height)
|
||||||
|
}
|
||||||
val upperPart = Rect(0, 0, width / 2, height)
|
val upperPart = Rect(0, 0, width / 2, height)
|
||||||
canvas.drawBitmap(imageBitmap, rightPart, upperPart, null)
|
canvas.drawBitmap(imageBitmap, rightPart, upperPart, null)
|
||||||
// left -> bottom
|
// left -> bottom
|
||||||
val leftPart = Rect(0, 0, width / 2, height)
|
val leftPart = when (upperSide) {
|
||||||
|
Side.LEFT -> Rect(width - width / 2, 0, width, height)
|
||||||
|
Side.RIGHT -> Rect(0, 0, width / 2, height)
|
||||||
|
}
|
||||||
val bottomPart = Rect(0, height, width / 2, height * 2)
|
val bottomPart = Rect(0, height, width / 2, height * 2)
|
||||||
canvas.drawBitmap(imageBitmap, leftPart, bottomPart, null)
|
canvas.drawBitmap(imageBitmap, leftPart, bottomPart, null)
|
||||||
|
|
||||||
|
@ -159,6 +159,16 @@
|
|||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
app:layout_constraintTop_toBottomOf="@id/fullscreen" />
|
app:layout_constraintTop_toBottomOf="@id/fullscreen" />
|
||||||
|
|
||||||
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
android:id="@+id/dual_page_invert"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/pref_dual_page_invert"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/dual_page_split"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
android:id="@+id/cutout_short"
|
android:id="@+id/cutout_short"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -166,7 +176,7 @@
|
|||||||
android:text="@string/pref_cutout_short"
|
android:text="@string/pref_cutout_short"
|
||||||
android:textColor="?android:attr/textColorSecondary"
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintTop_toBottomOf="@id/dual_page_split"
|
app:layout_constraintTop_toBottomOf="@id/dual_page_invert"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.switchmaterial.SwitchMaterial
|
<com.google.android.material.switchmaterial.SwitchMaterial
|
||||||
|
@ -251,6 +251,8 @@
|
|||||||
<!-- Reader section -->
|
<!-- Reader section -->
|
||||||
<string name="pref_fullscreen">Fullscreen</string>
|
<string name="pref_fullscreen">Fullscreen</string>
|
||||||
<string name="pref_dual_page_split">Dual page split (ALPHA)</string>
|
<string name="pref_dual_page_split">Dual page split (ALPHA)</string>
|
||||||
|
<string name="pref_dual_page_invert">Invert dual page split placement</string>
|
||||||
|
<string name="pref_dual_page_invert_summary">If the placement of the dual page split doesn\'t match reading direction</string>
|
||||||
<string name="pref_cutout_short">Show content in cutout area</string>
|
<string name="pref_cutout_short">Show content in cutout area</string>
|
||||||
<string name="pref_lock_orientation">Lock orientation</string>
|
<string name="pref_lock_orientation">Lock orientation</string>
|
||||||
<string name="pref_page_transitions">Animate page transitions</string>
|
<string name="pref_page_transitions">Animate page transitions</string>
|
||||||
|
Loading…
Reference in New Issue
Block a user