Taken from upstream with some tweaks: *Removed always show at start option *"Left" and "Right" in reader overlay now say "Next" or "Previous" in LRNav *Changing Inversion also shows navigation overlay *Show new user the nav overlay the first time for both paged and webview (since j2k has auto webtoon) Also unrelated, changed "page transitions" to "animate page transitions" Co-Authored-By: arkon <4098258+arkon@users.noreply.github.com>pull/7308/head
parent
380b609847
commit
999247d7dd
@ -0,0 +1,130 @@
|
||||
package eu.kanade.tachiyomi.ui.reader
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.util.AttributeSet
|
||||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import android.view.ViewPropertyAnimator
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.isVisible
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||
import kotlin.math.abs
|
||||
|
||||
class ReaderNavigationOverlayView(context: Context, attributeSet: AttributeSet) : View(context, attributeSet) {
|
||||
|
||||
private var viewPropertyAnimator: ViewPropertyAnimator? = null
|
||||
|
||||
private var navigation: ViewerNavigation? = null
|
||||
|
||||
var isLTR = true
|
||||
|
||||
fun setNavigation(navigation: ViewerNavigation, showOnStart: Boolean) {
|
||||
if (!showOnStart && (this.navigation == null || this.navigation === navigation) && !forceShowOverlay) {
|
||||
if (this.navigation == null) {
|
||||
this.navigation = navigation
|
||||
isVisible = false
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
forceShowOverlay = false
|
||||
this.navigation = navigation
|
||||
invalidate()
|
||||
|
||||
if (isVisible) return
|
||||
|
||||
viewPropertyAnimator = animate()
|
||||
.alpha(1f)
|
||||
.setDuration(FADE_DURATION)
|
||||
.withStartAction {
|
||||
isVisible = true
|
||||
}
|
||||
.withEndAction {
|
||||
viewPropertyAnimator = null
|
||||
}
|
||||
viewPropertyAnimator?.start()
|
||||
}
|
||||
|
||||
private val regionPaint = Paint()
|
||||
|
||||
private val textPaint = Paint().apply {
|
||||
textAlign = Paint.Align.CENTER
|
||||
color = Color.WHITE
|
||||
textSize = 64f
|
||||
}
|
||||
|
||||
private val textBorderPaint = Paint().apply {
|
||||
textAlign = Paint.Align.CENTER
|
||||
color = Color.BLACK
|
||||
textSize = 64f
|
||||
style = Paint.Style.STROKE
|
||||
strokeWidth = 8f
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas?) {
|
||||
if (navigation == null) return
|
||||
|
||||
navigation?.regions?.forEach {
|
||||
val region = it.invert(navigation!!.invertMode)
|
||||
val rect = region.rectF
|
||||
|
||||
canvas?.save()
|
||||
|
||||
// Scale rect from 1f,1f to screen width and height
|
||||
canvas?.scale(width.toFloat(), height.toFloat())
|
||||
val directionalRegion = region.type.directionalRegion(isLTR)
|
||||
regionPaint.color = ContextCompat.getColor(context, directionalRegion.colorRes)
|
||||
canvas?.drawRect(rect, regionPaint)
|
||||
|
||||
canvas?.restore()
|
||||
// Don't want scale anymore because it messes with drawText
|
||||
canvas?.save()
|
||||
|
||||
// Translate origin to rect start (left, top)
|
||||
canvas?.translate((width * rect.left), (height * rect.top))
|
||||
|
||||
// Calculate center of rect width on screen
|
||||
val x = width * (abs(rect.left - rect.right) / 2)
|
||||
|
||||
// Calculate center of rect height on screen
|
||||
val y = height * (abs(rect.top - rect.bottom) / 2)
|
||||
|
||||
canvas?.drawText(context.getString(directionalRegion.nameRes), x, y, textBorderPaint)
|
||||
canvas?.drawText(context.getString(directionalRegion.nameRes), x, y, textPaint)
|
||||
|
||||
canvas?.restore()
|
||||
}
|
||||
}
|
||||
|
||||
override fun performClick(): Boolean {
|
||||
super.performClick()
|
||||
|
||||
if (viewPropertyAnimator == null && isVisible) {
|
||||
viewPropertyAnimator = animate()
|
||||
.alpha(0f)
|
||||
.setDuration(FADE_DURATION)
|
||||
.withEndAction {
|
||||
isVisible = false
|
||||
viewPropertyAnimator = null
|
||||
}
|
||||
viewPropertyAnimator?.start()
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onTouchEvent(event: MotionEvent?): Boolean {
|
||||
// Hide overlay if user start tapping or swiping
|
||||
performClick()
|
||||
return super.onTouchEvent(event)
|
||||
}
|
||||
|
||||
companion object {
|
||||
var forceShowOverlay = false
|
||||
}
|
||||
}
|
||||
|
||||
private const val FADE_DURATION = 1000L
|
@ -0,0 +1,72 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer
|
||||
|
||||
import android.graphics.PointF
|
||||
import android.graphics.RectF
|
||||
import androidx.annotation.StringRes
|
||||
import eu.kanade.tachiyomi.R
|
||||
|
||||
abstract class ViewerNavigation {
|
||||
|
||||
sealed class NavigationRegion(@StringRes val nameRes: Int, val colorRes: Int) {
|
||||
object MENU : NavigationRegion(R.string.menu, R.color.navigation_menu)
|
||||
object PREV : NavigationRegion(R.string.previous, R.color.navigation_prev)
|
||||
object NEXT : NavigationRegion(R.string.next, R.color.navigation_next)
|
||||
object LEFT : NavigationRegion(R.string.left, R.color.navigation_left)
|
||||
object RIGHT : NavigationRegion(R.string.right, R.color.navigation_right)
|
||||
|
||||
fun directionalRegion(LTR: Boolean): NavigationRegion {
|
||||
return if (this === LEFT || this === RIGHT) {
|
||||
if (if (LTR) this === LEFT else this === RIGHT) NEXT else PREV
|
||||
}
|
||||
else this
|
||||
}
|
||||
}
|
||||
|
||||
data class Region(
|
||||
val rectF: RectF,
|
||||
val type: NavigationRegion
|
||||
) {
|
||||
fun invert(invertMode: TappingInvertMode): Region {
|
||||
if (invertMode == TappingInvertMode.NONE) return this
|
||||
return this.copy(
|
||||
rectF = this.rectF.invert(invertMode)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private var constantMenuRegion: RectF = RectF(0f, 0f, 1f, 0.05f)
|
||||
|
||||
abstract var regions: List<Region>
|
||||
|
||||
var invertMode: TappingInvertMode = TappingInvertMode.NONE
|
||||
|
||||
fun getAction(pos: PointF): NavigationRegion {
|
||||
val x = pos.x
|
||||
val y = pos.y
|
||||
val region = regions.map { it.invert(invertMode) }
|
||||
.find { it.rectF.contains(x, y) }
|
||||
return when {
|
||||
region != null -> region.type
|
||||
constantMenuRegion.contains(x, y) -> NavigationRegion.MENU
|
||||
else -> NavigationRegion.MENU
|
||||
}
|
||||
}
|
||||
|
||||
enum class TappingInvertMode(val shouldInvertHorizontal: Boolean = false, val shouldInvertVertical: Boolean = false) {
|
||||
NONE,
|
||||
HORIZONTAL(shouldInvertHorizontal = true),
|
||||
VERTICAL(shouldInvertVertical = true),
|
||||
BOTH(shouldInvertHorizontal = true, shouldInvertVertical = true)
|
||||
}
|
||||
}
|
||||
|
||||
fun RectF.invert(invertMode: ViewerNavigation.TappingInvertMode): RectF {
|
||||
val horizontal = invertMode.shouldInvertHorizontal
|
||||
val vertical = invertMode.shouldInvertVertical
|
||||
return when {
|
||||
horizontal && vertical -> RectF(1f - this.right, 1f - this.bottom, 1f - this.left, 1f - this.top)
|
||||
vertical -> RectF(this.left, 1f - this.bottom, this.right, 1f - this.top)
|
||||
horizontal -> RectF(1f - this.right, this.top, 1f - this.left, this.bottom)
|
||||
else -> this
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||
|
||||
import android.graphics.RectF
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||
|
||||
/**
|
||||
* Visualization of default state without any inversion
|
||||
* +---+---+---+
|
||||
* | N | N | N | P: Previous
|
||||
* +---+---+---+
|
||||
* | N | M | N | M: Menu
|
||||
* +---+---+---+
|
||||
* | N | P | N | N: Next
|
||||
* +---+---+---+
|
||||
*/
|
||||
class EdgeNavigation : ViewerNavigation() {
|
||||
|
||||
override var regions: List<Region> = listOf(
|
||||
Region(
|
||||
rectF = RectF(0f, 0f, 0.33f, 1f),
|
||||
type = NavigationRegion.NEXT
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0.33f, 0.66f, 0.66f, 1f),
|
||||
type = NavigationRegion.PREV
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0.66f, 0f, 1f, 1f),
|
||||
type = NavigationRegion.NEXT
|
||||
),
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||
|
||||
import android.graphics.RectF
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||
|
||||
/**
|
||||
* Visualization of default state without any inversion
|
||||
* +---+---+---+
|
||||
* | M | M | M | P: Previous
|
||||
* +---+---+---+
|
||||
* | P | N | N | M: Menu
|
||||
* +---+---+---+
|
||||
* | P | N | N | N: Next
|
||||
* +---+---+---+
|
||||
*/
|
||||
class KindlishNavigation : ViewerNavigation() {
|
||||
|
||||
override var regions: List<Region> = listOf(
|
||||
Region(
|
||||
rectF = RectF(0.33f, 0.33f, 1f, 1f),
|
||||
type = NavigationRegion.NEXT
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0f, 0.33f, 0.33f, 1f),
|
||||
type = NavigationRegion.PREV
|
||||
)
|
||||
)
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||
|
||||
import android.graphics.RectF
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||
|
||||
/**
|
||||
* Visualization of default state without any inversion
|
||||
* +---+---+---+
|
||||
* | P | P | P | P: Previous
|
||||
* +---+---+---+
|
||||
* | P | M | N | M: Menu
|
||||
* +---+---+---+
|
||||
* | N | N | N | N: Next
|
||||
* +---+---+---+
|
||||
*/
|
||||
open class LNavigation : ViewerNavigation() {
|
||||
|
||||
override var regions: List<Region> = listOf(
|
||||
Region(
|
||||
rectF = RectF(0f, 0.33f, 0.33f, 0.66f),
|
||||
type = NavigationRegion.PREV
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0f, 0f, 1f, 0.33f),
|
||||
type = NavigationRegion.PREV
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0.66f, 0.33f, 1f, 0.66f),
|
||||
type = NavigationRegion.NEXT
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0f, 0.66f, 1f, 1f),
|
||||
type = NavigationRegion.NEXT
|
||||
)
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
package eu.kanade.tachiyomi.ui.reader.viewer.navigation
|
||||
|
||||
import android.graphics.RectF
|
||||
import eu.kanade.tachiyomi.ui.reader.viewer.ViewerNavigation
|
||||
|
||||
/**
|
||||
* Visualization of default state without any inversion
|
||||
* +---+---+---+
|
||||
* | N | M | P | P: Move Right
|
||||
* +---+---+---+
|
||||
* | N | M | P | M: Menu
|
||||
* +---+---+---+
|
||||
* | N | M | P | N: Move Left
|
||||
* +---+---+---+
|
||||
*/
|
||||
class RightAndLeftNavigation : ViewerNavigation() {
|
||||
|
||||
override var regions: List<Region> = listOf(
|
||||
Region(
|
||||
rectF = RectF(0f, 0f, 0.33f, 1f),
|
||||
type = NavigationRegion.LEFT
|
||||
),
|
||||
Region(
|
||||
rectF = RectF(0.66f, 0f, 1f, 1f),
|
||||
type = NavigationRegion.RIGHT
|
||||
),
|
||||
)
|
||||
}
|
Loading…
Reference in new issue