diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 27d81469fc..45ae284484 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -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") 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 04ff9ec2ff..09e32a31c6 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 @@ -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) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt index fe9c9ecdf8..b0b1582c43 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryController.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt index e7f153accb..b94fb85742 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryHeaderItem.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt index 98d281a521..e7cd4143e8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/library/filter/FilterBottomSheet.kt @@ -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) diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt index 7841a0500f..7489435818 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsAdapter.kt @@ -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>(controller) { val preferences: PreferencesHelper by injectLazy() + val hasShownSwipeTut + get() = preferences.shownChapterSwipeTutorial() + var items: List = emptyList() val delegate: MangaDetailsInterface = controller diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt index cde0e28d9f..815b921e20 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaDetailsController.kt @@ -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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt index 6ebe8e5553..da3c28696b 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/chapter/ChapterHolder.kt @@ -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 { diff --git a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt index 853e8ba0bf..140f24d3a3 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/widget/SimpleAnimationListener.kt @@ -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) + } +} diff --git a/app/src/main/res/layout/filter_bottom_sheet.xml b/app/src/main/res/layout/filter_bottom_sheet.xml index 8c7f6b2e63..dff4b703b9 100644 --- a/app/src/main/res/layout/filter_bottom_sheet.xml +++ b/app/src/main/res/layout/filter_bottom_sheet.xml @@ -1,7 +1,7 @@ diff --git a/app/src/main/res/layout/reader_settings_sheet.xml b/app/src/main/res/layout/reader_settings_sheet.xml index 39865f0441..a18f91b185 100644 --- a/app/src/main/res/layout/reader_settings_sheet.xml +++ b/app/src/main/res/layout/reader_settings_sheet.xml @@ -2,7 +2,7 @@ + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools" + app:tint="@android:color/black" + tools:context=".MainActivity"> - - + app:showAsAction="ifRoom" /> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8b5b6a29dc..badbe38330 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -140,7 +140,7 @@ Hide badges Show badges Show count - To show filters again, tap the Library icon + Tap the Library icon to show filters Display as