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:
Andreas 2021-03-20 20:36:01 +01:00 committed by GitHub
parent d912a42249
commit 5a7f2684b3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 195 additions and 0 deletions

View file

@ -79,6 +79,10 @@ object PreferenceKeys {
const val navigationModeWebtoon = "reader_navigation_mode_webtoon" 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 webtoonSidePadding = "webtoon_side_padding"
const val portraitColumns = "pref_library_columns_portrait_key" const val portraitColumns = "pref_library_columns_portrait_key"

View file

@ -149,6 +149,10 @@ class PreferencesHelper(val context: Context) {
fun navigationModeWebtoon() = flowPrefs.getInt(Keys.navigationModeWebtoon, 0) 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 portraitColumns() = flowPrefs.getInt(Keys.portraitColumns, 0)
fun landscapeColumns() = flowPrefs.getInt(Keys.landscapeColumns, 0) fun landscapeColumns() = flowPrefs.getInt(Keys.landscapeColumns, 0)

View file

@ -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)
}
}

View file

@ -15,6 +15,8 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
var imagePropertyChangedListener: (() -> Unit)? = null var imagePropertyChangedListener: (() -> Unit)? = null
var navigationModeChangedListener: (() -> Unit)? = null
var tappingEnabled = true var tappingEnabled = true
var tappingInverted = TappingInvertMode.NONE var tappingInverted = TappingInvertMode.NONE
var longTapEnabled = true var longTapEnabled = true
@ -27,6 +29,10 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
var navigationMode = 0 var navigationMode = 0
protected set protected set
var forceNavigationOverlay = false
var navigationOverlayOnStart = false
var dualPageSplit = false var dualPageSplit = false
protected set protected set
@ -60,6 +66,14 @@ abstract class ViewerConfig(preferences: PreferencesHelper, private val scope: C
preferences.alwaysShowChapterTransition() preferences.alwaysShowChapterTransition()
.register({ alwaysShowChapterTransition = it }) .register({ alwaysShowChapterTransition = it })
forceNavigationOverlay = preferences.showNavigationOverlayNewUser().get()
if (forceNavigationOverlay) {
preferences.showNavigationOverlayNewUser().set(false)
}
preferences.showNavigationOverlayOnStart()
.register({ navigationOverlayOnStart = it })
} }
protected abstract fun defaultNavigation(): ViewerNavigation protected abstract fun defaultNavigation(): ViewerNavigation

View file

@ -90,6 +90,7 @@ class PagerConfig(
4 -> RightAndLeftNavigation() 4 -> RightAndLeftNavigation()
else -> defaultNavigation() else -> defaultNavigation()
} }
navigationModeChangedListener?.invoke()
} }
enum class ZoomType { enum class ZoomType {

View file

@ -119,6 +119,11 @@ abstract class PagerViewer(val activity: ReaderActivity) : BaseViewer {
config.imagePropertyChangedListener = { config.imagePropertyChangedListener = {
refreshAdapter() refreshAdapter()
} }
config.navigationModeChangedListener = {
val showOnStart = config.navigationOverlayOnStart || config.forceNavigationOverlay
activity.binding.navigationOverlay.setNavigation(config.navigator, showOnStart)
}
} }
override fun destroy() { override fun destroy() {

View file

@ -63,5 +63,6 @@ class WebtoonConfig(
4 -> RightAndLeftNavigation() 4 -> RightAndLeftNavigation()
else -> defaultNavigation() else -> defaultNavigation()
} }
navigationModeChangedListener?.invoke()
} }
} }

View file

@ -136,6 +136,11 @@ class WebtoonViewer(val activity: ReaderActivity, val isContinuous: Boolean = tr
refreshAdapter() 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.layoutParams = ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT)
frame.addView(recycler) frame.addView(recycler)
} }

View file

@ -50,6 +50,12 @@ class SettingsReaderController : SettingsController() {
summaryRes = R.string.pref_show_reading_mode_summary summaryRes = R.string.pref_show_reading_mode_summary
defaultValue = true 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) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
switchPreference { switchPreference {
key = Keys.trueColor key = Keys.trueColor

View file

@ -43,6 +43,12 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:visibility="gone" /> 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 <FrameLayout
android:id="@+id/reader_menu" android:id="@+id/reader_menu"
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -76,4 +76,11 @@
<color name="green">#47a84a</color> <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> </resources>

View file

@ -252,6 +252,8 @@
<!-- Reader section --> <!-- Reader section -->
<string name="pref_fullscreen">Fullscreen</string> <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_split">Dual page split (ALPHA)</string>
<string name="pref_dual_page_invert">Invert dual page split placement</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_dual_page_invert_summary">If the placement of the dual page split doesn\'t match reading direction</string>