Unify list spacing approach
parent
61a7f1c830
commit
2342594885
@ -1,106 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.core.ui
|
|
||||||
|
|
||||||
import android.app.Dialog
|
|
||||||
import android.os.Bundle
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.view.ViewGroup.LayoutParams
|
|
||||||
import androidx.activity.OnBackPressedDispatcher
|
|
||||||
import androidx.core.view.updateLayoutParams
|
|
||||||
import androidx.viewbinding.ViewBinding
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.core.ui.dialog.AppBottomSheetDialog
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.findActivity
|
|
||||||
import org.koitharu.kotatsu.core.util.ext.getDisplaySize
|
|
||||||
import com.google.android.material.R as materialR
|
|
||||||
|
|
||||||
@Deprecated(
|
|
||||||
"Use BaseAdaptiveSheet",
|
|
||||||
replaceWith = ReplaceWith("BaseAdaptiveSheet<B>", "org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet"),
|
|
||||||
)
|
|
||||||
abstract class BaseBottomSheet<B : ViewBinding> : BottomSheetDialogFragment() {
|
|
||||||
|
|
||||||
var viewBinding: B? = null
|
|
||||||
private set
|
|
||||||
|
|
||||||
@Deprecated("", ReplaceWith("requireViewBinding()"))
|
|
||||||
protected val binding: B
|
|
||||||
get() = requireViewBinding()
|
|
||||||
|
|
||||||
protected val behavior: BottomSheetBehavior<*>?
|
|
||||||
get() = (dialog as? BottomSheetDialog)?.behavior
|
|
||||||
|
|
||||||
val isExpanded: Boolean
|
|
||||||
get() = behavior?.state == BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
|
|
||||||
val onBackPressedDispatcher: OnBackPressedDispatcher
|
|
||||||
get() = (requireDialog() as AppBottomSheetDialog).onBackPressedDispatcher
|
|
||||||
|
|
||||||
final override fun onCreateView(
|
|
||||||
inflater: LayoutInflater,
|
|
||||||
container: ViewGroup?,
|
|
||||||
savedInstanceState: Bundle?,
|
|
||||||
): View {
|
|
||||||
val binding = onCreateViewBinding(inflater, container)
|
|
||||||
viewBinding = binding
|
|
||||||
return binding.root
|
|
||||||
}
|
|
||||||
|
|
||||||
final override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
|
||||||
super.onViewCreated(view, savedInstanceState)
|
|
||||||
val binding = requireViewBinding()
|
|
||||||
// Enforce max width for tablets
|
|
||||||
val width = resources.getDimensionPixelSize(R.dimen.bottom_sheet_width)
|
|
||||||
if (width > 0) {
|
|
||||||
behavior?.maxWidth = width
|
|
||||||
}
|
|
||||||
// Set peek height to 40% display height
|
|
||||||
binding.root.context.findActivity()?.getDisplaySize()?.let {
|
|
||||||
behavior?.peekHeight = (it.height() * 0.4).toInt()
|
|
||||||
}
|
|
||||||
onViewBindingCreated(binding, savedInstanceState)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDestroyView() {
|
|
||||||
viewBinding = null
|
|
||||||
super.onDestroyView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
|
||||||
return AppBottomSheetDialog(requireContext(), theme)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun addBottomSheetCallback(callback: BottomSheetBehavior.BottomSheetCallback) {
|
|
||||||
val b = behavior ?: return
|
|
||||||
b.addBottomSheetCallback(callback)
|
|
||||||
val rootView = dialog?.findViewById<View>(materialR.id.design_bottom_sheet)
|
|
||||||
if (rootView != null) {
|
|
||||||
callback.onStateChanged(rootView, b.state)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): B
|
|
||||||
|
|
||||||
protected open fun onViewBindingCreated(binding: B, savedInstanceState: Bundle?) = Unit
|
|
||||||
|
|
||||||
protected fun setExpanded(isExpanded: Boolean, isLocked: Boolean) {
|
|
||||||
val b = behavior ?: return
|
|
||||||
if (isExpanded) {
|
|
||||||
b.state = BottomSheetBehavior.STATE_EXPANDED
|
|
||||||
}
|
|
||||||
b.isFitToContents = !isExpanded
|
|
||||||
val rootView = dialog?.findViewById<View>(materialR.id.design_bottom_sheet)
|
|
||||||
rootView?.updateLayoutParams {
|
|
||||||
height = if (isExpanded) LayoutParams.MATCH_PARENT else LayoutParams.WRAP_CONTENT
|
|
||||||
}
|
|
||||||
b.isDraggable = !isLocked
|
|
||||||
}
|
|
||||||
|
|
||||||
fun requireViewBinding(): B = checkNotNull(viewBinding) {
|
|
||||||
"Fragment $this did not return a ViewBinding from onCreateView() or this was called before onCreateView()."
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,35 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.core.ui.list.decor
|
|
||||||
|
|
||||||
import android.graphics.Rect
|
|
||||||
import android.util.SparseIntArray
|
|
||||||
import android.view.View
|
|
||||||
import androidx.core.util.getOrDefault
|
|
||||||
import androidx.core.util.set
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
|
|
||||||
class TypedSpacingItemDecoration(
|
|
||||||
vararg spacingMapping: Pair<Int, Int>,
|
|
||||||
private val fallbackSpacing: Int = 0,
|
|
||||||
) : RecyclerView.ItemDecoration() {
|
|
||||||
|
|
||||||
private val mapping = SparseIntArray(spacingMapping.size)
|
|
||||||
|
|
||||||
init {
|
|
||||||
spacingMapping.forEach { (k, v) -> mapping[k] = v }
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemOffsets(
|
|
||||||
outRect: Rect,
|
|
||||||
view: View,
|
|
||||||
parent: RecyclerView,
|
|
||||||
state: RecyclerView.State
|
|
||||||
) {
|
|
||||||
val itemType = parent.getChildViewHolder(view)?.itemViewType
|
|
||||||
val spacing = if (itemType == null) {
|
|
||||||
fallbackSpacing
|
|
||||||
} else {
|
|
||||||
mapping.getOrDefault(itemType, fallbackSpacing)
|
|
||||||
}
|
|
||||||
outRect.set(spacing, spacing, spacing, spacing)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,28 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.filter.ui
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.graphics.Rect
|
|
||||||
import android.view.View
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
|
|
||||||
class FilterItemDecoration(
|
|
||||||
context: Context,
|
|
||||||
) : RecyclerView.ItemDecoration() {
|
|
||||||
|
|
||||||
private val spacing = context.resources.getDimensionPixelOffset(R.dimen.list_spacing)
|
|
||||||
|
|
||||||
override fun getItemOffsets(
|
|
||||||
outRect: Rect,
|
|
||||||
view: View,
|
|
||||||
parent: RecyclerView,
|
|
||||||
state: RecyclerView.State
|
|
||||||
) {
|
|
||||||
val itemType = parent.getChildViewHolder(view)?.itemViewType ?: -1
|
|
||||||
if (itemType == FilterAdapter.ITEM_TYPE_HEADER) {
|
|
||||||
outRect.set(spacing, 0, spacing, 0)
|
|
||||||
} else {
|
|
||||||
outRect.set(0, 0, 0, 0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,25 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
enum class ListItemType {
|
||||||
|
|
||||||
|
FILTER_SORT,
|
||||||
|
FILTER_TAG,
|
||||||
|
HEADER,
|
||||||
|
MANGA_LIST,
|
||||||
|
MANGA_LIST_DETAILED,
|
||||||
|
MANGA_GRID,
|
||||||
|
FOOTER_LOADING,
|
||||||
|
FOOTER_ERROR,
|
||||||
|
STATE_LOADING,
|
||||||
|
STATE_ERROR,
|
||||||
|
STATE_EMPTY,
|
||||||
|
EXPLORE_BUTTONS,
|
||||||
|
EXPLORE_SOURCE_GRID,
|
||||||
|
EXPLORE_SOURCE_LIST,
|
||||||
|
EXPLORE_SUGGESTION,
|
||||||
|
TIP,
|
||||||
|
HINT_EMPTY,
|
||||||
|
PAGE_THUMB,
|
||||||
|
FEED,
|
||||||
|
DOWNLOAD,
|
||||||
|
}
|
||||||
@ -0,0 +1,56 @@
|
|||||||
|
package org.koitharu.kotatsu.list.ui.adapter
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import androidx.recyclerview.widget.RecyclerView.ItemDecoration
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
|
||||||
|
class TypedListSpacingDecoration(
|
||||||
|
context: Context,
|
||||||
|
) : ItemDecoration() {
|
||||||
|
|
||||||
|
private val spacingList = context.resources.getDimensionPixelOffset(R.dimen.list_spacing)
|
||||||
|
private val spacingGrid = context.resources.getDimensionPixelOffset(R.dimen.grid_spacing)
|
||||||
|
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State
|
||||||
|
) {
|
||||||
|
val itemType = parent.getChildViewHolder(view)?.itemViewType?.let {
|
||||||
|
ListItemType.values().getOrNull(it)
|
||||||
|
}
|
||||||
|
when (itemType) {
|
||||||
|
ListItemType.FILTER_SORT,
|
||||||
|
ListItemType.FILTER_TAG -> outRect.set(0)
|
||||||
|
|
||||||
|
ListItemType.HEADER -> outRect.set(spacingList, 0, spacingList, 0)
|
||||||
|
ListItemType.MANGA_LIST -> outRect.set(0)
|
||||||
|
ListItemType.DOWNLOAD,
|
||||||
|
ListItemType.MANGA_LIST_DETAILED -> outRect.set(spacingList)
|
||||||
|
|
||||||
|
ListItemType.PAGE_THUMB,
|
||||||
|
ListItemType.MANGA_GRID -> outRect.set(spacingGrid)
|
||||||
|
|
||||||
|
ListItemType.FOOTER_LOADING,
|
||||||
|
ListItemType.FOOTER_ERROR,
|
||||||
|
ListItemType.STATE_LOADING,
|
||||||
|
ListItemType.STATE_ERROR,
|
||||||
|
ListItemType.STATE_EMPTY,
|
||||||
|
ListItemType.EXPLORE_BUTTONS,
|
||||||
|
ListItemType.EXPLORE_SOURCE_GRID,
|
||||||
|
ListItemType.EXPLORE_SOURCE_LIST,
|
||||||
|
ListItemType.EXPLORE_SUGGESTION,
|
||||||
|
null -> outRect.set(0)
|
||||||
|
|
||||||
|
ListItemType.TIP -> outRect.set(0) // TODO
|
||||||
|
ListItemType.HINT_EMPTY -> outRect.set(0) // TODO
|
||||||
|
ListItemType.FEED -> outRect.set(0) // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Rect.set(spacing: Int) = set(spacing, spacing, spacing, spacing)
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue