From 5a7f2684b354943758475b9fe329f233b4295a84 Mon Sep 17 00:00:00 2001 From: Andreas Date: Sat, 20 Mar 2021 20:36:01 +0100 Subject: [PATCH] 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 --- .../data/preference/PreferenceKeys.kt | 4 + .../data/preference/PreferencesHelper.kt | 4 + .../ui/reader/ReaderNavigationOverlayView.kt | 140 ++++++++++++++++++ .../ui/reader/viewer/ViewerConfig.kt | 14 ++ .../ui/reader/viewer/pager/PagerConfig.kt | 1 + .../ui/reader/viewer/pager/PagerViewer.kt | 5 + .../ui/reader/viewer/webtoon/WebtoonConfig.kt | 1 + .../ui/reader/viewer/webtoon/WebtoonViewer.kt | 5 + .../ui/setting/SettingsReaderController.kt | 6 + app/src/main/res/layout/reader_activity.xml | 6 + app/src/main/res/values/colors.xml | 7 + app/src/main/res/values/strings.xml | 2 + 12 files changed, 195 insertions(+) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderNavigationOverlayView.kt diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt index cb91777b2..622d5da23 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferenceKeys.kt @@ -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" diff --git a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt index 09b6ef143..65b02c323 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/data/preference/PreferencesHelper.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderNavigationOverlayView.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderNavigationOverlayView.kt new file mode 100644 index 000000000..13e0b22f0 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderNavigationOverlayView.kt @@ -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) + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt index 95184c0cd..79f8b8374 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/ViewerConfig.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt index 1e134ba83..0f835e74c 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerConfig.kt @@ -90,6 +90,7 @@ class PagerConfig( 4 -> RightAndLeftNavigation() else -> defaultNavigation() } + navigationModeChangedListener?.invoke() } enum class ZoomType { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt index 5265423ab..039d1e63b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewer.kt @@ -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() { diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt index f427cff4c..f59a96a91 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonConfig.kt @@ -63,5 +63,6 @@ class WebtoonConfig( 4 -> RightAndLeftNavigation() else -> defaultNavigation() } + navigationModeChangedListener?.invoke() } } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt index a132199d5..991c89df7 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/webtoon/WebtoonViewer.kt @@ -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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt index 443375f10..a3e0aa065 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/setting/SettingsReaderController.kt @@ -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 diff --git a/app/src/main/res/layout/reader_activity.xml b/app/src/main/res/layout/reader_activity.xml index f12965ffe..ec537b1f1 100644 --- a/app/src/main/res/layout/reader_activity.xml +++ b/app/src/main/res/layout/reader_activity.xml @@ -43,6 +43,12 @@ android:layout_height="match_parent" android:visibility="gone" /> + + #47a84a + + #CB84E296 + #CCFF7733 + #CC95818D + #CCA6CFD5 + #CC7D1128 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 83380e22b..d26dc8e4d 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -252,6 +252,8 @@ Fullscreen + Show navigation layout overlay + Show overlay when reader is opened Dual page split (ALPHA) Invert dual page split placement If the placement of the dual page split doesn\'t match reading direction