mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-11-10 16:37:48 +01:00
Add navigation layout overlay (#4683)
* Add navigation layout overlay * Minor clean up Destroy animator when done not on start Move and change pref title Add summary
This commit is contained in:
parent
d912a42249
commit
5a7f2684b3
12 changed files with 195 additions and 0 deletions
|
@ -79,6 +79,10 @@ object PreferenceKeys {
|
|||
|
||||
const val navigationModeWebtoon = "reader_navigation_mode_webtoon"
|
||||
|
||||
const val showNavigationOverlayNewUser = "reader_navigation_overlay_new_user"
|
||||
|
||||
const val showNavigationOverlayOnStart = "reader_navigation_overlay_on_start"
|
||||
|
||||
const val webtoonSidePadding = "webtoon_side_padding"
|
||||
|
||||
const val portraitColumns = "pref_library_columns_portrait_key"
|
||||
|
|
|
@ -149,6 +149,10 @@ class PreferencesHelper(val context: Context) {
|
|||
|
||||
fun navigationModeWebtoon() = flowPrefs.getInt(Keys.navigationModeWebtoon, 0)
|
||||
|
||||
fun showNavigationOverlayNewUser() = flowPrefs.getBoolean(Keys.showNavigationOverlayNewUser, true)
|
||||
|
||||
fun showNavigationOverlayOnStart() = flowPrefs.getBoolean(Keys.showNavigationOverlayOnStart, false)
|
||||
|
||||
fun portraitColumns() = flowPrefs.getInt(Keys.portraitColumns, 0)
|
||||
|
||||
fun landscapeColumns() = flowPrefs.getInt(Keys.landscapeColumns, 0)
|
||||
|
|
|
@ -0,0 +1,140 @@
|
|||
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.R
|
||||
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
|
||||
|
||||
fun setNavigation(navigation: ViewerNavigation, showOnStart: Boolean) {
|
||||
if (!showOnStart && this.navigation == null) {
|
||||
this.navigation = navigation
|
||||
isVisible = false
|
||||
return
|
||||
}
|
||||
|
||||
this.navigation = navigation
|
||||
invalidate()
|
||||
|
||||
if (isVisible) return
|
||||
|
||||
viewPropertyAnimator = animate()
|
||||
.alpha(1f)
|
||||
.setDuration(1000L)
|
||||
.withStartAction {
|
||||
isVisible = true
|
||||
}
|
||||
.withEndAction {
|
||||
viewPropertyAnimator = null
|
||||
}
|
||||
viewPropertyAnimator?.start()
|
||||
}
|
||||
|
||||
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 { region ->
|
||||
|
||||
val paint = paintForRegion(region.type)
|
||||
|
||||
val rect = region.rectF
|
||||
|
||||
canvas?.save()
|
||||
|
||||
// Scale rect from 1f,1f to screen width and height
|
||||
canvas?.scale(width.toFloat(), height.toFloat())
|
||||
canvas?.drawRect(rect, paint)
|
||||
|
||||
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(region.type.name, x, y, textBorderPaint)
|
||||
canvas?.drawText(region.type.name, x, y, textPaint)
|
||||
|
||||
canvas?.restore()
|
||||
}
|
||||
}
|
||||
|
||||
private fun paintForRegion(type: ViewerNavigation.NavigationRegion): Paint {
|
||||
return Paint().apply {
|
||||
when (type) {
|
||||
ViewerNavigation.NavigationRegion.NEXT -> {
|
||||
color = ContextCompat.getColor(context, R.color.navigation_next)
|
||||
}
|
||||
ViewerNavigation.NavigationRegion.PREV -> {
|
||||
color = ContextCompat.getColor(context, R.color.navigation_prev)
|
||||
}
|
||||
ViewerNavigation.NavigationRegion.MENU -> {
|
||||
color = ContextCompat.getColor(context, R.color.navigation_menu)
|
||||
}
|
||||
ViewerNavigation.NavigationRegion.RIGHT -> {
|
||||
color = ContextCompat.getColor(context, R.color.navigation_right)
|
||||
}
|
||||
ViewerNavigation.NavigationRegion.LEFT -> {
|
||||
color = ContextCompat.getColor(context, R.color.navigation_left)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun performClick(): Boolean {
|
||||
super.performClick()
|
||||
|
||||
if (viewPropertyAnimator == null && isVisible) {
|
||||
viewPropertyAnimator = animate()
|
||||
.alpha(0f)
|
||||
.setDuration(1000L)
|
||||
.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)
|
||||
}
|
||||
}
|
|
@ -15,6 +15,8 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
|
|||
|
||||
var imagePropertyChangedListener: (() -> Unit)? = null
|
||||
|
||||
var navigationModeChangedListener: (() -> Unit)? = null
|
||||
|
||||
var tappingEnabled = true
|
||||
var tappingInverted = TappingInvertMode.NONE
|
||||
var longTapEnabled = true
|
||||
|
@ -27,6 +29,10 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
|
|||
var navigationMode = 0
|
||||
protected set
|
||||
|
||||
var forceNavigationOverlay = false
|
||||
|
||||
var navigationOverlayOnStart = false
|
||||
|
||||
var dualPageSplit = false
|
||||
protected set
|
||||
|
||||
|
@ -60,6 +66,14 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
|
|||
|
||||
preferences.alwaysShowChapterTransition()
|
||||
.register({ alwaysShowChapterTransition = it })
|
||||
|
||||
forceNavigationOverlay = preferences.showNavigationOverlayNewUser().get()
|
||||
if (forceNavigationOverlay) {
|
||||
preferences.showNavigationOverlayNewUser().set(false)
|
||||
}
|
||||
|
||||
preferences.showNavigationOverlayOnStart()
|
||||
.register({ navigationOverlayOnStart = it })
|
||||
}
|
||||
|
||||
protected abstract fun defaultNavigation(): ViewerNavigation
|
||||
|
|
|
@ -90,6 +90,7 @@ class PagerConfig(
|
|||
4 -> RightAndLeftNavigation()
|
||||
else -> defaultNavigation()
|
||||
}
|
||||
navigationModeChangedListener?.invoke()
|
||||
}
|
||||
|
||||
enum class ZoomType {
|
||||
|
|
|
@ -119,6 +119,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
|
|||
config.imagePropertyChangedListener = {
|
||||
refreshAdapter()
|
||||
}
|
||||
|
||||
config.navigationModeChangedListener = {
|
||||
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart)
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
|
|
|
@ -63,5 +63,6 @@ class WebtoonConfig(
|
|||
4 -> RightAndLeftNavigation()
|
||||
else -> defaultNavigation()
|
||||
}
|
||||
navigationModeChangedListener?.invoke()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -136,6 +136,11 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
|
|||
refreshAdapter()
|
||||
}
|
||||
|
||||
config.navigationModeChangedListener = {
|
||||
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
|
||||
activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart)
|
||||
}
|
||||
|
||||
frame.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
|
||||
frame.addView(recycler)
|
||||
}
|
||||
|
|
|
@ -50,6 +50,12 @@ class SettingsReaderController : SettingsController() {
|
|||
summaryRes = R.string.pref_show_reading_mode_summary
|
||||
defaultValue = true
|
||||
}
|
||||
switchPreference {
|
||||
key = Keys.showNavigationOverlayOnStart
|
||||
titleRes = R.string.pref_show_navigation_mode
|
||||
summaryRes = R.string.pref_show_navigation_mode_summary
|
||||
defaultValue = false
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
switchPreference {
|
||||
key = Keys.trueColor
|
||||
|
|
|
@ -43,6 +43,12 @@
|
|||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<eu.kanade.tachiyomi.ui.reader.ReaderNavigationOverlayView
|
||||
android:id="@+id/navigation_overlay"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:visibility="gone" />
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/reader_menu"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -76,4 +76,11 @@
|
|||
|
||||
<color name="green">#47a84a</color>
|
||||
|
||||
<!-- Navigation overlay colors -->
|
||||
<color name="navigation_next">#CB84E296</color>
|
||||
<color name="navigation_prev">#CCFF7733</color>
|
||||
<color name="navigation_menu">#CC95818D</color>
|
||||
<color name="navigation_right">#CCA6CFD5</color>
|
||||
<color name="navigation_left">#CC7D1128</color>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -252,6 +252,8 @@
|
|||
|
||||
<!-- Reader section -->
|
||||
<string name="pref_fullscreen">Fullscreen</string>
|
||||
<string name="pref_show_navigation_mode">Show navigation layout overlay</string>
|
||||
<string name="pref_show_navigation_mode_summary">Show overlay when reader is opened</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>
|
||||
|
|
Loading…
Reference in a new issue