mirror of
https://github.com/tachiyomiorg/tachiyomi.git
synced 2024-09-11 14:43:13 +02:00
MaterialMenuSheet now uses a recyclerview
Also moved whats new sheet to mainactivity as a function
This commit is contained in:
parent
d0af0ddffe
commit
8753d188d1
@ -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
|
||||
)
|
||||
}
|
||||
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
)
|
@ -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">
|
||||
|
Loading…
Reference in New Issue
Block a user