MaterialMenuSheet now uses a recyclerview

Also moved whats new sheet to mainactivity as a function
This commit is contained in:
Jays2Kings 2021-04-26 04:43:52 -04:00
parent d0af0ddffe
commit 8753d188d1
5 changed files with 153 additions and 124 deletions

View File

@ -2,30 +2,30 @@ package eu.kanade.tachiyomi.ui.base
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.os.Build
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.isVisible
import com.google.android.material.bottomsheet.BottomSheetBehavior
import eu.kanade.tachiyomi.R
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.adapters.ItemAdapter
import eu.kanade.tachiyomi.databinding.BottomMenuSheetBinding
import eu.kanade.tachiyomi.util.system.dpToPx
import eu.kanade.tachiyomi.util.system.hasSideNavBar
import eu.kanade.tachiyomi.util.system.isInNightMode
import eu.kanade.tachiyomi.util.view.RecyclerWindowInsetsListener
import eu.kanade.tachiyomi.util.view.checkHeightThen
import eu.kanade.tachiyomi.util.view.expand
import eu.kanade.tachiyomi.util.view.setBottomEdge
import eu.kanade.tachiyomi.util.view.updateLayoutParams
import eu.kanade.tachiyomi.widget.EdgeToEdgeBottomSheetDialog
import eu.kanade.tachiyomi.widget.MenuSheetItemView
import kotlin.math.min
@SuppressLint("InflateParams")
open class MaterialMenuSheet(
class MaterialMenuSheet(
activity: Activity,
items: List<MenuSheetItem>,
title: String? = null,
@ -36,73 +36,61 @@ open class MaterialMenuSheet(
) : EdgeToEdgeBottomSheetDialog<BottomMenuSheetBinding>(activity) {
override fun createBinding(inflater: LayoutInflater) = BottomMenuSheetBinding.inflate(inflater)
private val fastAdapter: FastAdapter<MaterialMenuSheetItem>
private val itemAdapter = ItemAdapter<MaterialMenuSheetItem>()
override var recyclerView: RecyclerView? = binding.menuSheetRecycler
init {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !context.isInNightMode() && !activity.window.decorView.rootWindowInsets.hasSideNavBar()) {
window?.decorView?.systemUiVisibility = View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
}
if (maxHeight != null) {
binding.menuScrollView.maxHeight = maxHeight + activity.window.decorView.rootWindowInsets.systemWindowInsetBottom
binding.menuScrollView.requestLayout()
} else {
binding.titleLayout.viewTreeObserver.addOnGlobalLayoutListener {
binding.menuScrollView.updateLayoutParams<ConstraintLayout.LayoutParams> {
val fullHeight = activity.window.decorView.height
val insets = activity.window.decorView.rootWindowInsets
matchConstraintMaxHeight =
binding.menuSheetLayout.checkHeightThen {
binding.menuSheetRecycler.updateLayoutParams<ConstraintLayout.LayoutParams> {
val fullHeight = activity.window.decorView.height
val insets = activity.window.decorView.rootWindowInsets
matchConstraintMaxHeight =
min(
(maxHeight ?: fullHeight) + (insets?.systemWindowInsetBottom ?: 0),
fullHeight - (insets?.systemWindowInsetTop ?: 0) -
binding.titleLayout.height - 26.dpToPx
}
binding.titleLayout.height - 26.dpToPx
)
}
}
binding.divider.isVisible = showDivider
var currentIndex: Int? = null
items.forEachIndexed { index, item ->
val view =
activity.layoutInflater.inflate(R.layout.menu_sheet_item, null) as MenuSheetItemView
if (index == 0 && title == null) {
view.setBackgroundResource(R.drawable.rounded_item_background)
}
with(view) {
id = item.id
binding.menuLayout.addView(this)
if (item.text != null) {
text = item.text
} else {
setText(item.textRes)
}
setIcon(item.drawable)
if (item.drawable == 0) {
textSize = 14f
}
if (item.id == selectedId) {
currentIndex = index
isSelected = true
}
setOnClickListener {
val shouldDismiss = onMenuItemClicked(this@MaterialMenuSheet, id)
if (shouldDismiss) {
dismiss()
}
}
fastAdapter = FastAdapter.with(itemAdapter)
fastAdapter.setHasStableIds(true)
itemAdapter.set(items.map(::MaterialMenuSheetItem))
binding.menuSheetRecycler.layoutManager = LinearLayoutManager(context)
binding.menuSheetRecycler.adapter = fastAdapter
fastAdapter.onClickListener = { _, _, item, _ ->
val shouldDismiss = onMenuItemClicked(this@MaterialMenuSheet, item.sheetItem.id)
if (shouldDismiss) {
dismiss()
}
false
}
BottomSheetBehavior.from(binding.root.parent as ViewGroup).expand()
BottomSheetBehavior.from(binding.root.parent as ViewGroup).skipCollapsed = true
setBottomEdge(binding.menuLayout, activity)
sheetBehavior.expand()
sheetBehavior.skipCollapsed = true
binding.menuSheetRecycler.setOnApplyWindowInsetsListener(RecyclerWindowInsetsListener)
binding.titleLayout.isVisible = title != null
binding.toolbarTitle.text = title
currentIndex?.let {
if (selectedId != null) {
itemAdapter.getAdapterItem(selectedId).isSelected = true
binding.root.post {
binding.menuScrollView.scrollTo(0, it * 48.dpToPx - binding.menuScrollView.height / 2)
binding.root.post {
binding.menuSheetRecycler.scrollBy(
0,
selectedId * 48.dpToPx - binding.menuSheetRecycler.height / 2
)
}
}
}
@ -117,38 +105,41 @@ open class MaterialMenuSheet(
binding.titleLayout,
"elevation",
binding.titleLayout.elevation,
if (elevate) 10f else 0f
if (elevate) 5f else 0f
)
elevationAnimator?.start()
}
elevate(binding.menuScrollView.canScrollVertically(-1))
elevate(binding.menuSheetRecycler.canScrollVertically(-1))
if (binding.titleLayout.isVisible) {
binding.menuScrollView.setOnScrollChangeListener { _: View?, _: Int, _: Int, _: Int, _: Int ->
val notAtTop = binding.menuScrollView.canScrollVertically(-1)
if (notAtTop != isElevated) {
elevate(notAtTop)
binding.menuSheetRecycler.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
val notAtTop = binding.menuSheetRecycler.canScrollVertically(-1)
if (notAtTop != isElevated) {
elevate(notAtTop)
}
}
}
})
}
}
private fun clearEndDrawables() {
(0 until binding.menuLayout.childCount).forEach {
(binding.menuLayout.getChildAt(it) as? MenuSheetItemView)?.isSelected = false
}
itemAdapter.adapterItems.forEach { it.isSelected = false }
}
fun setDrawable(id: Int, @DrawableRes drawableRes: Int, clearAll: Boolean = true) {
if (clearAll) {
clearEndDrawables()
}
binding.menuLayout.findViewById<MenuSheetItemView>(id)?.selectWithEndIcon(drawableRes)
itemAdapter.getAdapterItem(id).sheetItem.endDrawableRes = drawableRes
itemAdapter.getAdapterItem(id).isSelected = true
fastAdapter.notifyAdapterDataSetChanged()
}
data class MenuSheetItem(
val id: Int,
@DrawableRes val drawable: Int = 0,
@StringRes val textRes: Int = 0,
val text: String? = null
val text: String? = null,
var endDrawableRes: Int = 0
)
}

View File

@ -0,0 +1,50 @@
package eu.kanade.tachiyomi.ui.base
import android.view.View
import com.mikepenz.fastadapter.FastAdapter
import com.mikepenz.fastadapter.items.AbstractItem
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.databinding.MenuSheetItemBinding
class MaterialMenuSheetItem(val sheetItem: MaterialMenuSheet.MenuSheetItem) : AbstractItem<MaterialMenuSheetItem.ViewHolder>() {
/** defines the type defining this item. must be unique. preferably an id */
override val type: Int = R.id.item_text_view
/**
* Returns the layout resource for this item.
*/
override val layoutRes: Int = R.layout.menu_sheet_item
override var identifier = sheetItem.id.hashCode().toLong()
override fun getViewHolder(v: View): ViewHolder {
return ViewHolder(v)
}
class ViewHolder(view: View) : FastAdapter.ViewHolder<MaterialMenuSheetItem>(view) {
private val binding = MenuSheetItemBinding.bind(view)
override fun bindView(item: MaterialMenuSheetItem, payloads: List<Any>) {
val sheetItem = item.sheetItem
with(binding.root) {
if (sheetItem.text != null) {
text = sheetItem.text
} else {
setText(sheetItem.textRes)
}
setIcon(sheetItem.drawable)
if (sheetItem.drawable == 0) {
textSize = 14f
}
isSelected = this.isSelected
if (isSelected) {
selectWithEndIcon(sheetItem.endDrawableRes)
}
}
}
override fun unbindView(item: MaterialMenuSheetItem) {
}
}
}

View File

@ -25,6 +25,7 @@ import androidx.appcompat.graphics.drawable.DrawerArrowDrawable
import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.core.graphics.ColorUtils
import androidx.core.net.toUri
import androidx.core.view.GestureDetectorCompat
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
@ -50,6 +51,7 @@ import eu.kanade.tachiyomi.data.updater.UpdateChecker
import eu.kanade.tachiyomi.data.updater.UpdateResult
import eu.kanade.tachiyomi.databinding.MainActivityBinding
import eu.kanade.tachiyomi.extension.api.ExtensionGithubApi
import eu.kanade.tachiyomi.ui.base.MaterialMenuSheet
import eu.kanade.tachiyomi.ui.base.activity.BaseActivity
import eu.kanade.tachiyomi.ui.base.controller.BaseController
import eu.kanade.tachiyomi.ui.base.controller.DialogController
@ -69,6 +71,7 @@ import eu.kanade.tachiyomi.util.system.getResourceColor
import eu.kanade.tachiyomi.util.system.hasSideNavBar
import eu.kanade.tachiyomi.util.system.isBottomTappable
import eu.kanade.tachiyomi.util.system.launchUI
import eu.kanade.tachiyomi.util.system.toast
import eu.kanade.tachiyomi.util.view.doOnApplyWindowInsets
import eu.kanade.tachiyomi.util.view.getItemView
import eu.kanade.tachiyomi.util.view.snack
@ -326,7 +329,7 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
if (Migrations.upgrade(preferences)) {
if (!BuildConfig.DEBUG) {
content.post {
WhatsNewSheet(this).show()
whatsNewSheet().show()
}
}
}
@ -800,6 +803,39 @@ open class MainActivity : BaseActivity<MainActivityBinding>(), DownloadServiceLi
}
}
private fun whatsNewSheet() = MaterialMenuSheet(
this,
listOf(
MaterialMenuSheet.MenuSheetItem(
0,
textRes = R.string.whats_new_this_release,
drawable = R.drawable.ic_new_releases_24dp
),
MaterialMenuSheet.MenuSheetItem(
1,
textRes = R.string.close,
drawable = R.drawable.ic_close_24dp
)
),
title = getString(R.string.updated_to_, BuildConfig.VERSION_NAME),
showDivider = true,
selectedId = 0,
onMenuItemClicked = { _, item ->
if (item == 0) {
try {
val intent = Intent(
Intent.ACTION_VIEW,
"https://github.com/jays2kings/tachiyomiJ2K/releases/tag/v${BuildConfig.VERSION_NAME}".toUri()
)
startActivity(intent)
} catch (e: Throwable) {
toast(e.message)
}
}
true
}
)
private inner class GestureListener : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent): Boolean {
return true

View File

@ -1,42 +0,0 @@
package eu.kanade.tachiyomi.ui.main
import android.app.Activity
import android.content.Intent
import androidx.core.net.toUri
import eu.kanade.tachiyomi.BuildConfig
import eu.kanade.tachiyomi.R
import eu.kanade.tachiyomi.ui.base.MaterialMenuSheet
import eu.kanade.tachiyomi.util.system.toast
class WhatsNewSheet(activity: Activity) : MaterialMenuSheet(
activity,
listOf(
MenuSheetItem(
0,
textRes = R.string.whats_new_this_release,
drawable = R.drawable.ic_new_releases_24dp
),
MenuSheetItem(
1,
textRes = R.string.close,
drawable = R.drawable.ic_close_24dp
)
),
title = activity.getString(R.string.updated_to_, BuildConfig.VERSION_NAME),
showDivider = true,
selectedId = 0,
onMenuItemClicked = { _, item ->
if (item == 0) {
try {
val intent = Intent(
Intent.ACTION_VIEW,
"https://github.com/jays2kings/tachiyomiJ2K/releases/tag/v${BuildConfig.VERSION_NAME}".toUri()
)
activity.startActivity(intent)
} catch (e: Throwable) {
activity.toast(e.message)
}
}
true
}
)

View File

@ -2,30 +2,24 @@
<androidx.constraintlayout.widget.ConstraintLayout 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/source_filter_sheet"
android:id="@+id/menu_sheet_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/bottom_sheet_rounded_background"
app:layout_constraintVertical_chainStyle="packed"
android:backgroundTint="?android:attr/colorBackground">
<eu.kanade.tachiyomi.ui.base.MaxHeightScrollView
android:id="@+id/menu_scroll_view"
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/menu_sheet_recycler"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:clipToPadding="false"
app:layout_constraintStart_toStartOf="parent"
app:layout_constrainedHeight="true"
app:layout_constraintTop_toBottomOf="@id/title_layout">
<LinearLayout
android:id="@+id/menu_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" />
</eu.kanade.tachiyomi.ui.base.MaxHeightScrollView>
</androidx.recyclerview.widget.RecyclerView>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/title_layout"
@ -38,7 +32,7 @@
android:elevation="0dp"
android:focusable="true"
android:orientation="horizontal"
app:layout_constraintBottom_toTopOf="@id/menu_scroll_view"
app:layout_constraintBottom_toTopOf="@id/menu_sheet_recycler"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">