diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheet.kt index f1c935ec29..ce824024a8 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheet.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheet.kt @@ -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, title: String? = null, @@ -36,73 +36,61 @@ open class MaterialMenuSheet( ) : EdgeToEdgeBottomSheetDialog(activity) { override fun createBinding(inflater: LayoutInflater) = BottomMenuSheetBinding.inflate(inflater) + private val fastAdapter: FastAdapter + private val itemAdapter = ItemAdapter() + + 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 { - val fullHeight = activity.window.decorView.height - val insets = activity.window.decorView.rootWindowInsets - matchConstraintMaxHeight = + binding.menuSheetLayout.checkHeightThen { + binding.menuSheetRecycler.updateLayoutParams { + 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(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 ) } diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheetItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheetItem.kt new file mode 100644 index 0000000000..559051321d --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/base/MaterialMenuSheetItem.kt @@ -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() { + + /** 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(view) { + + private val binding = MenuSheetItemBinding.bind(view) + override fun bindView(item: MaterialMenuSheetItem, payloads: List) { + 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) { + } + } +} diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt index 0deae94ec5..6a6e4a1458 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt @@ -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(), DownloadServiceLi if (Migrations.upgrade(preferences)) { if (!BuildConfig.DEBUG) { content.post { - WhatsNewSheet(this).show() + whatsNewSheet().show() } } } @@ -800,6 +803,39 @@ open class MainActivity : BaseActivity(), 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 diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/main/WhatsNewSheet.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/main/WhatsNewSheet.kt deleted file mode 100644 index df0e94ebb6..0000000000 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/main/WhatsNewSheet.kt +++ /dev/null @@ -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 - } -) diff --git a/app/src/main/res/layout/bottom_menu_sheet.xml b/app/src/main/res/layout/bottom_menu_sheet.xml index b5453b4ffd..fdac7831c4 100644 --- a/app/src/main/res/layout/bottom_menu_sheet.xml +++ b/app/src/main/res/layout/bottom_menu_sheet.xml @@ -2,30 +2,24 @@ - - - +