Add "Rotate wide pages to fit" setting for paged reader
Originally authored in #7983 Co-authored-by: timothyng-164 <timothyng-164@users.noreply.github.com> (cherry picked from commit 953720472fe64ef488ecae7ae7fea453b8c7c68b) # Conflicts: # app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderReadingModeSettings.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt # app/src/main/res/layout/reader_pager_settings.xml
This commit is contained in:
parent
be17682e3c
commit
880b06dd3b
@ -183,10 +183,12 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
val navModePref = readerPreferences.navigationModePager()
|
val navModePref = readerPreferences.navigationModePager()
|
||||||
val imageScaleTypePref = readerPreferences.imageScaleType()
|
val imageScaleTypePref = readerPreferences.imageScaleType()
|
||||||
val dualPageSplitPref = readerPreferences.dualPageSplitPaged()
|
val dualPageSplitPref = readerPreferences.dualPageSplitPaged()
|
||||||
|
val rotateToFitPref = readerPreferences.dualPageRotateToFit()
|
||||||
|
|
||||||
val navMode by navModePref.collectAsState()
|
val navMode by navModePref.collectAsState()
|
||||||
val imageScaleType by imageScaleTypePref.collectAsState()
|
val imageScaleType by imageScaleTypePref.collectAsState()
|
||||||
val dualPageSplit by dualPageSplitPref.collectAsState()
|
val dualPageSplit by dualPageSplitPref.collectAsState()
|
||||||
|
val rotateToFit by rotateToFitPref.collectAsState()
|
||||||
|
|
||||||
return Preference.PreferenceGroup(
|
return Preference.PreferenceGroup(
|
||||||
title = stringResource(R.string.pager_viewer),
|
title = stringResource(R.string.pager_viewer),
|
||||||
@ -255,6 +257,10 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
pref = dualPageSplitPref,
|
pref = dualPageSplitPref,
|
||||||
title = stringResource(R.string.pref_dual_page_split),
|
title = stringResource(R.string.pref_dual_page_split),
|
||||||
|
onValueChanged = {
|
||||||
|
rotateToFitPref.set(false)
|
||||||
|
true
|
||||||
|
},
|
||||||
),
|
),
|
||||||
Preference.PreferenceItem.SwitchPreference(
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
pref = readerPreferences.dualPageInvertPaged(),
|
pref = readerPreferences.dualPageInvertPaged(),
|
||||||
@ -262,6 +268,19 @@ object SettingsReaderScreen : SearchableSettings {
|
|||||||
subtitle = stringResource(R.string.pref_dual_page_invert_summary),
|
subtitle = stringResource(R.string.pref_dual_page_invert_summary),
|
||||||
enabled = dualPageSplit,
|
enabled = dualPageSplit,
|
||||||
),
|
),
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = rotateToFitPref,
|
||||||
|
title = stringResource(R.string.pref_page_rotate),
|
||||||
|
onValueChanged = {
|
||||||
|
dualPageSplitPref.set(false)
|
||||||
|
true
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Preference.PreferenceItem.SwitchPreference(
|
||||||
|
pref = readerPreferences.dualPageRotateToFitInvert(),
|
||||||
|
title = stringResource(R.string.pref_page_rotate_invert),
|
||||||
|
enabled = rotateToFit,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -78,6 +78,10 @@ class ReaderPreferences(
|
|||||||
|
|
||||||
fun dualPageInvertWebtoon() = preferenceStore.getBoolean("pref_dual_page_invert_webtoon", false)
|
fun dualPageInvertWebtoon() = preferenceStore.getBoolean("pref_dual_page_invert_webtoon", false)
|
||||||
|
|
||||||
|
fun dualPageRotateToFit() = preferenceStore.getBoolean("pref_dual_page_rotate", false)
|
||||||
|
|
||||||
|
fun dualPageRotateToFitInvert() = preferenceStore.getBoolean("pref_dual_page_rotate_invert", false)
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
// region Color filter
|
// region Color filter
|
||||||
|
@ -92,12 +92,27 @@ class ReaderReadingModeSettings @JvmOverloads constructor(context: Context, attr
|
|||||||
binding.pagerPrefsGroup.cropBorders.bindToPreference(readerPreferences.cropBorders())
|
binding.pagerPrefsGroup.cropBorders.bindToPreference(readerPreferences.cropBorders())
|
||||||
|
|
||||||
binding.pagerPrefsGroup.dualPageSplit.bindToPreference(readerPreferences.dualPageSplitPaged())
|
binding.pagerPrefsGroup.dualPageSplit.bindToPreference(readerPreferences.dualPageSplitPaged())
|
||||||
// Makes it so that dual page invert gets hidden away when dual page split is turned off
|
|
||||||
readerPreferences.dualPageSplitPaged()
|
readerPreferences.dualPageSplitPaged()
|
||||||
.asHotFlow { binding.pagerPrefsGroup.dualPageInvert.isVisible = it }
|
.asHotFlow {
|
||||||
|
binding.pagerPrefsGroup.dualPageInvert.isVisible = it
|
||||||
|
if (it) {
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFit.isChecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
.launchIn((context as ReaderActivity).lifecycleScope)
|
.launchIn((context as ReaderActivity).lifecycleScope)
|
||||||
binding.pagerPrefsGroup.dualPageInvert.bindToPreference(readerPreferences.dualPageInvertPaged())
|
binding.pagerPrefsGroup.dualPageInvert.bindToPreference(readerPreferences.dualPageInvertPaged())
|
||||||
|
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFit.bindToPreference(readerPreferences.dualPageRotateToFit())
|
||||||
|
readerPreferences.dualPageRotateToFit()
|
||||||
|
.asHotFlow {
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFitInvert.isVisible = it
|
||||||
|
if (it) {
|
||||||
|
binding.pagerPrefsGroup.dualPageSplit.isChecked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.launchIn((context as ReaderActivity).lifecycleScope)
|
||||||
|
binding.pagerPrefsGroup.dualPageRotateToFitInvert.bindToPreference(readerPreferences.dualPageRotateToFitInvert())
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
binding.pagerPrefsGroup.pageTransitionsPager.bindToPreference(readerPreferences.pageTransitionsPager())
|
binding.pagerPrefsGroup.pageTransitionsPager.bindToPreference(readerPreferences.pageTransitionsPager())
|
||||||
binding.pagerPrefsGroup.pageLayout.bindToPreference(readerPreferences.pageLayout())
|
binding.pagerPrefsGroup.pageLayout.bindToPreference(readerPreferences.pageLayout())
|
||||||
|
@ -36,6 +36,12 @@ abstract class ViewerConfig(readerPreferences: ReaderPreferences, private val sc
|
|||||||
var dualPageInvert = false
|
var dualPageInvert = false
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
|
var dualPageRotateToFit = false
|
||||||
|
protected set
|
||||||
|
|
||||||
|
var dualPageRotateToFitInvert = false
|
||||||
|
protected set
|
||||||
|
|
||||||
abstract var navigator: ViewerNavigation
|
abstract var navigator: ViewerNavigation
|
||||||
protected set
|
protected set
|
||||||
|
|
||||||
|
@ -123,6 +123,18 @@ class PagerConfig(
|
|||||||
readerPreferences.dualPageInvertPaged()
|
readerPreferences.dualPageInvertPaged()
|
||||||
.register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() })
|
.register({ dualPageInvert = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
|
||||||
|
readerPreferences.dualPageRotateToFit()
|
||||||
|
.register(
|
||||||
|
{ dualPageRotateToFit = it },
|
||||||
|
{ imagePropertyChangedListener?.invoke() },
|
||||||
|
)
|
||||||
|
|
||||||
|
readerPreferences.dualPageRotateToFitInvert()
|
||||||
|
.register(
|
||||||
|
{ dualPageRotateToFitInvert = it },
|
||||||
|
{ imagePropertyChangedListener?.invoke() },
|
||||||
|
)
|
||||||
|
|
||||||
// SY -->
|
// SY -->
|
||||||
readerPreferences.pageTransitionsPager()
|
readerPreferences.pageTransitionsPager()
|
||||||
.register({ usePageTransitions = it }, { imagePropertyChangedListener?.invoke() })
|
.register({ usePageTransitions = it }, { imagePropertyChangedListener?.invoke() })
|
||||||
|
@ -210,6 +210,10 @@ class PagerPageHolder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun process(page: ReaderPage, imageStream: BufferedInputStream): InputStream {
|
private fun process(page: ReaderPage, imageStream: BufferedInputStream): InputStream {
|
||||||
|
if (viewer.config.dualPageRotateToFit) {
|
||||||
|
return rotateDualPage(imageStream)
|
||||||
|
}
|
||||||
|
|
||||||
if (!viewer.config.dualPageSplit) {
|
if (!viewer.config.dualPageSplit) {
|
||||||
return imageStream
|
return imageStream
|
||||||
}
|
}
|
||||||
@ -228,6 +232,16 @@ class PagerPageHolder(
|
|||||||
return splitInHalf(imageStream)
|
return splitInHalf(imageStream)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun rotateDualPage(imageStream: BufferedInputStream): InputStream {
|
||||||
|
val isDoublePage = ImageUtil.isWideImage(imageStream)
|
||||||
|
return if (isDoublePage) {
|
||||||
|
val rotation = if (viewer.config.dualPageRotateToFitInvert) -90f else 90f
|
||||||
|
ImageUtil.rotateImage(imageStream, rotation)
|
||||||
|
} else {
|
||||||
|
imageStream
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun mergePages(imageStream: InputStream, imageStream2: InputStream?): InputStream {
|
private fun mergePages(imageStream: InputStream, imageStream2: InputStream?): InputStream {
|
||||||
// Handle adding a center margin to wide images if requested
|
// Handle adding a center margin to wide images if requested
|
||||||
if (imageStream2 == null) {
|
if (imageStream2 == null) {
|
||||||
|
@ -98,6 +98,26 @@
|
|||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/dual_page_rotate_to_fit"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="16dp"
|
||||||
|
android:text="@string/pref_page_rotate"
|
||||||
|
android:textColor="?android:attr/textColorSecondary" />
|
||||||
|
|
||||||
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
|
android:id="@+id/dual_page_rotate_to_fit_invert"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingHorizontal="16dp"
|
||||||
|
android:paddingVertical="16dp"
|
||||||
|
android:text="@string/pref_page_rotate_invert"
|
||||||
|
android:textColor="?android:attr/textColorSecondary"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:visibility="visible" />
|
||||||
|
|
||||||
<com.google.android.material.materialswitch.MaterialSwitch
|
<com.google.android.material.materialswitch.MaterialSwitch
|
||||||
android:id="@+id/page_transitions_pager"
|
android:id="@+id/page_transitions_pager"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
@ -127,6 +147,6 @@
|
|||||||
android:id="@+id/tapping_prefs_group"
|
android:id="@+id/tapping_prefs_group"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
app:constraint_referenced_ids="pager_nav,tapping_inverted,dual_page_split,dual_page_invert,page_transitions_pager" />
|
app:constraint_referenced_ids="pager_nav,tapping_inverted,dual_page_split,dual_page_invert,dual_page_rotate_to_fit,dual_page_rotate_to_fit_invert,page_transitions_pager" />
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
@ -8,6 +8,7 @@ import android.graphics.BitmapFactory
|
|||||||
import android.graphics.BitmapRegionDecoder
|
import android.graphics.BitmapRegionDecoder
|
||||||
import android.graphics.Canvas
|
import android.graphics.Canvas
|
||||||
import android.graphics.Color
|
import android.graphics.Color
|
||||||
|
import android.graphics.Matrix
|
||||||
import android.graphics.Rect
|
import android.graphics.Rect
|
||||||
import android.graphics.drawable.ColorDrawable
|
import android.graphics.drawable.ColorDrawable
|
||||||
import android.graphics.drawable.Drawable
|
import android.graphics.drawable.Drawable
|
||||||
@ -152,6 +153,23 @@ object ImageUtil {
|
|||||||
return ByteArrayInputStream(output.toByteArray())
|
return ByteArrayInputStream(output.toByteArray())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun rotateImage(imageStream: InputStream, degrees: Float): InputStream {
|
||||||
|
val imageBytes = imageStream.readBytes()
|
||||||
|
|
||||||
|
val imageBitmap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)
|
||||||
|
val rotated = rotateBitMap(imageBitmap, degrees)
|
||||||
|
|
||||||
|
val output = ByteArrayOutputStream()
|
||||||
|
rotated.compress(Bitmap.CompressFormat.JPEG, 100, output)
|
||||||
|
|
||||||
|
return ByteArrayInputStream(output.toByteArray())
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun rotateBitMap(bitmap: Bitmap, degrees: Float): Bitmap {
|
||||||
|
val matrix = Matrix().apply { postRotate(degrees) }
|
||||||
|
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Split the image into left and right parts, then merge them into a
|
* Split the image into left and right parts, then merge them into a
|
||||||
* new vertically-aligned image.
|
* new vertically-aligned image.
|
||||||
|
@ -314,6 +314,8 @@
|
|||||||
<string name="pref_dual_page_split">Split wide pages</string>
|
<string name="pref_dual_page_split">Split wide pages</string>
|
||||||
<string name="pref_dual_page_invert">Invert split page placement</string>
|
<string name="pref_dual_page_invert">Invert split page placement</string>
|
||||||
<string name="pref_dual_page_invert_summary">If the placement of the split wide pages don\'t match reading direction</string>
|
<string name="pref_dual_page_invert_summary">If the placement of the split wide pages don\'t match reading direction</string>
|
||||||
|
<string name="pref_page_rotate">Rotate wide pages to fit</string>
|
||||||
|
<string name="pref_page_rotate_invert">Flip orientation of rotated wide pages</string>
|
||||||
<string name="pref_long_strip_split">Split tall images (BETA)</string>
|
<string name="pref_long_strip_split">Split tall images (BETA)</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_page_transitions">Animate page transitions</string>
|
<string name="pref_page_transitions">Animate page transitions</string>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user