Added Tips for filters and chapter swipe

Using tooltip library to showtips
Swipe animations for first chapter item
Flow preferences to handle this
This commit is contained in:
Jay 2020-04-25 00:47:01 -04:00
parent 3bee24e79a
commit e9efc7d020
14 changed files with 118 additions and 26 deletions

View File

@ -204,6 +204,7 @@ dependencies {
implementation("com.github.kizitonwose:AndroidTagGroup:1.6.0")
implementation("com.github.chrisbanes:PhotoView:2.3.0")
implementation("com.github.carlosesco:DirectionalViewPager:a844dbca0a")
implementation("com.github.florent37:viewtooltip:1.2.2")
// Conductor
implementation("com.bluelinelabs:conductor:2.1.5")

View File

@ -7,6 +7,7 @@ import android.os.Environment
import androidx.preference.PreferenceManager
import com.f2prateek.rx.preferences.Preference
import com.f2prateek.rx.preferences.RxSharedPreferences
import com.tfcporciuncula.flow.FlowSharedPreferences
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.track.TrackService
import eu.kanade.tachiyomi.source.Source
@ -40,6 +41,7 @@ class PreferencesHelper(val context: Context) {
private val prefs = PreferenceManager.getDefaultSharedPreferences(context)
private val rxPrefs = RxSharedPreferences.create(prefs)
private val flowPrefs = FlowSharedPreferences(prefs)
private val defaultDownloadsDir = Uri.fromFile(
File(Environment.getExternalStorageDirectory().absolutePath + File.separator +
@ -258,4 +260,9 @@ class PreferencesHelper(val context: Context) {
fun hideFiltersAtStart() = rxPrefs.getBoolean("hide_filters_at_start", false)
fun alwaysShowChapterTransition() = rxPrefs.getBoolean(Keys.alwaysShowChapterTransition, true)
// Tutorial preference
fun shownFilterTutorial() = flowPrefs.getBoolean("shown_filter_tutorial", false)
fun shownChapterSwipeTutorial() = flowPrefs.getBoolean("shown_swipe_tutorial", false)
}

View File

@ -14,7 +14,6 @@ import android.view.View
import android.view.ViewGroup
import android.view.ViewPropertyAnimator
import android.view.inputmethod.InputMethodManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.view.ActionMode
import androidx.appcompat.widget.SearchView
@ -27,6 +26,7 @@ import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItemsSingleChoice
import com.bluelinelabs.conductor.ControllerChangeHandler
import com.bluelinelabs.conductor.ControllerChangeType
import com.github.florent37.viewtooltip.ViewTooltip
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.snackbar.BaseTransientBottomBar
import com.google.android.material.snackbar.Snackbar
@ -57,7 +57,6 @@ import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.dpToPxEnd
import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.applyWindowInsetsForRootController
import eu.kanade.tachiyomi.util.view.getItemView
import eu.kanade.tachiyomi.util.view.gone
@ -140,6 +139,7 @@ class LibraryController(
private var textAnim: ViewPropertyAnimator? = null
private var scrollAnim: ViewPropertyAnimator? = null
private var alwaysShowScroller: Boolean = preferences.alwaysShowSeeker().getOrDefault()
private var filterTooltip: ViewTooltip? = null
override fun getTitle(): String? {
return view?.context?.getString(R.string.library)
@ -198,6 +198,28 @@ class LibraryController(
}
}
private fun showFilterTip() {
if (preferences.shownFilterTutorial().get()) return
val activity = activity ?: return
val icon = activity.bottom_nav.getItemView(R.id.nav_library) ?: return
filterTooltip =
ViewTooltip.on(activity, icon).autoHide(false, 0L).align(ViewTooltip.ALIGN.START)
.position(ViewTooltip.Position.TOP).text(R.string.tap_library_to_show_filters)
.color(activity.getResourceColor(R.attr.colorAccent))
.textSize(TypedValue.COMPLEX_UNIT_SP, 15f).textColor(Color.WHITE).withShadow(false)
.corner(30).arrowWidth(15).arrowHeight(15).distanceWithView(0)
filterTooltip?.show()
}
private fun closeTip() {
if (filterTooltip != null) {
filterTooltip?.close()
filterTooltip = null
preferences.shownFilterTutorial().set(true)
}
}
private fun hideScroller(duration: Long = 1000) {
if (alwaysShowScroller) return
scrollAnim =
@ -447,7 +469,7 @@ class LibraryController(
presenter.getLibrary()
DownloadService.callListeners()
LibraryUpdateService.setListener(this)
}
} else closeTip()
if (type == ControllerChangeType.POP_ENTER) filter_bottom_sheet.hideIfPossible()
}
@ -836,6 +858,7 @@ class LibraryController(
}
override fun showSheet() {
closeTip()
when {
filter_bottom_sheet.sheetBehavior?.state == BottomSheetBehavior.STATE_HIDDEN -> filter_bottom_sheet.sheetBehavior?.state =
BottomSheetBehavior.STATE_COLLAPSED

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.ui.library
import android.annotation.SuppressLint
import android.graphics.drawable.Drawable
import android.text.SpannableString
import android.text.style.ForegroundColorSpan
@ -164,6 +165,8 @@ class LibraryHeaderItem(
updateButton.invisible()
}
}
@SuppressLint("RestrictedApi")
private fun showCatSortOptions() {
val category =
(adapter.getItem(adapterPosition) as? LibraryHeaderItem)?.category ?: return

View File

@ -133,6 +133,7 @@ class FilterBottomSheet @JvmOverloads constructor(context: Context, attrs: Attri
pill.alpha = 0f
}
if (state == BottomSheetBehavior.STATE_HIDDEN) {
onGroupClicked(ACTION_HIDE_FILTER_TIP)
reSortViews()
shadow?.alpha = 0f
pager?.updatePaddingRelative(bottom = 0)

View File

@ -1,6 +1,5 @@
package eu.kanade.tachiyomi.ui.manga
import android.content.Context
import android.view.View
import androidx.recyclerview.widget.ItemTouchHelper
import eu.davidea.flexibleadapter.items.IFlexible
@ -13,12 +12,14 @@ import java.text.DecimalFormat
import java.text.DecimalFormatSymbols
class MangaDetailsAdapter(
val controller: MangaDetailsController,
context: Context
val controller: MangaDetailsController
) : BaseChapterAdapter<IFlexible<*>>(controller) {
val preferences: PreferencesHelper by injectLazy()
val hasShownSwipeTut
get() = preferences.shownChapterSwipeTutorial()
var items: List<ChapterItem> = emptyList()
val delegate: MangaDetailsInterface = controller

View File

@ -231,7 +231,7 @@ class MangaDetailsController : BaseController,
width = ViewGroup.LayoutParams.MATCH_PARENT
}
tabletRecycler?.clipToPadding = false
tabletAdapter = MangaDetailsAdapter(this, view.context)
tabletAdapter = MangaDetailsAdapter(this)
tabletRecycler?.adapter = tabletAdapter
tabletRecycler?.layoutManager = LinearLayoutManager(view.context)
val divider = View(view.context)
@ -246,7 +246,7 @@ class MangaDetailsController : BaseController,
/** Set adapter, insets, and scroll listener for recycler view */
private fun setRecycler(view: View) {
adapter = MangaDetailsAdapter(this, view.context)
adapter = MangaDetailsAdapter(this)
recycler.adapter = adapter
adapter?.isSwipeEnabled = true

View File

@ -1,5 +1,7 @@
package eu.kanade.tachiyomi.ui.manga.chapter
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.view.View
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.data.database.models.Manga
@ -7,8 +9,13 @@ import eu.kanade.tachiyomi.data.download.model.Download
import eu.kanade.tachiyomi.source.LocalSource
import eu.kanade.tachiyomi.ui.manga.MangaDetailsAdapter
import eu.kanade.tachiyomi.util.chapter.ChapterUtil
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.view.gone
import eu.kanade.tachiyomi.util.view.isVisible
import eu.kanade.tachiyomi.util.view.visible
import eu.kanade.tachiyomi.util.view.visibleIf
import eu.kanade.tachiyomi.widget.EndAnimatorListener
import eu.kanade.tachiyomi.widget.StartAnimatorListener
import kotlinx.android.synthetic.main.chapters_item.*
import kotlinx.android.synthetic.main.download_button.*
@ -86,6 +93,39 @@ class ChapterHolder(
notifyStatus(status, item.isLocked, item.progress)
resetFrontView()
if (adapterPosition == 1) {
if (!adapter.hasShownSwipeTut.get())
showSlideAnimation()
}
}
private fun showSlideAnimation() {
val slide = 100f.dpToPx
val animatorSet = AnimatorSet()
val anim1 = slideAnimation(0f, slide)
anim1.startDelay = 1000
anim1.addListener(StartAnimatorListener { left_view.visible() })
val anim2 = slideAnimation(slide, -slide)
anim2.duration = 600
anim2.startDelay = 500
anim2.addUpdateListener {
if (left_view.isVisible() && front_view.translationX <= 0) {
left_view.gone()
right_view.visible()
}
}
val anim3 = slideAnimation(-slide, 0f)
anim3.startDelay = 750
animatorSet.playSequentially(anim1, anim2, anim3)
animatorSet.addListener(EndAnimatorListener {
adapter.hasShownSwipeTut.set(true)
})
animatorSet.start()
}
private fun slideAnimation(from: Float, to: Float): ObjectAnimator {
return ObjectAnimator.ofFloat(front_view, View.TRANSLATION_X, from, to)
.setDuration(300)
}
override fun getFrontView(): View {

View File

@ -1,5 +1,6 @@
package eu.kanade.tachiyomi.widget
import android.animation.Animator
import android.view.animation.Animation
open class SimpleAnimationListener : Animation.AnimationListener {
@ -9,3 +10,27 @@ open class SimpleAnimationListener : Animation.AnimationListener {
override fun onAnimationStart(animation: Animation) {}
}
open class SimpleAnimatorListener : Animator.AnimatorListener {
override fun onAnimationCancel(animation: Animator?) {}
override fun onAnimationRepeat(animator: Animator) {}
override fun onAnimationEnd(animator: Animator) {}
override fun onAnimationStart(animator: Animator) {}
}
class StartAnimatorListener(private val startAnimationListener: (animator: Animator) -> Unit) :
SimpleAnimatorListener() {
override fun onAnimationStart(animator: Animator) {
startAnimationListener(animator)
}
}
class EndAnimatorListener(private val endAnimationListener: (animator: Animator) -> Unit) :
SimpleAnimatorListener() {
override fun onAnimationEnd(animator: Animator) {
endAnimationListener(animator)
}
}

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<eu.kanade.tachiyomi.ui.library.filter.FilterBottomSheet xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/bottom_sheet"
android:id="@+id/filter_bottom_sheet"
style="@style/BottomSheetDialogTheme"
android:layout_width="match_parent"
android:layout_height="wrap_content"

View File

@ -77,7 +77,7 @@
android:alpha="0.5"
android:background="@drawable/shape_gradient_top_shadow"
android:paddingBottom="10dp"
app:layout_anchor="@id/bottom_sheet"
app:layout_anchor="@id/filter_bottom_sheet"
app:layout_anchorGravity="top" />
<!-- Adding bottom sheet after main content -->

View File

@ -2,7 +2,7 @@
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/bottom_sheet"
android:id="@+id/filter_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_sheet_rounded_background"

View File

@ -1,8 +1,8 @@
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".MainActivity"
app:tint="@android:color/black">
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
app:tint="@android:color/black"
tools:context=".MainActivity">
<item
android:id="@+id/action_search"
@ -12,19 +12,10 @@
app:actionViewClass="androidx.appcompat.widget.SearchView"
app:showAsAction="collapseActionView|ifRoom" />
<item
android:id="@+id/action_library_display"
android:icon="@drawable/ic_tune_white_24dp"
android:visible="false"
android:title="@string/display_options"
app:showAsAction="ifRoom"
/>
<item
android:id="@+id/action_settings"
android:icon="@drawable/ic_settings_white_24dp"
android:title="@string/settings"
app:showAsAction="ifRoom"
/>
app:showAsAction="ifRoom" />
</menu>

View File

@ -140,7 +140,7 @@
<string name="hide_badges">Hide badges</string>
<string name="show_badges">Show badges</string>
<string name="show_count">Show count</string>
<string name="hide_filters_tip">To show filters again, tap the Library icon</string>
<string name="tap_library_to_show_filters">Tap the Library icon to show filters</string>
<string name="display_as">Display as</string>
<!-- Library update service notifications -->