Use SideSheet instead of BottomSheet on landscape
This commit is contained in:
@@ -18,6 +18,10 @@ 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
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
package org.koitharu.kotatsu.core.ui.sheet
|
||||
|
||||
import android.app.Dialog
|
||||
import android.view.View
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.BottomSheetCallback
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||
import com.google.android.material.sidesheet.SideSheetBehavior
|
||||
import com.google.android.material.sidesheet.SideSheetCallback
|
||||
import com.google.android.material.sidesheet.SideSheetDialog
|
||||
import java.util.LinkedList
|
||||
|
||||
sealed class AdaptiveSheetBehavior {
|
||||
|
||||
@JvmField
|
||||
protected val callbacks = LinkedList<AdaptiveSheetCallback>()
|
||||
|
||||
abstract var state: Int
|
||||
|
||||
abstract var isDraggable: Boolean
|
||||
|
||||
open val isHideable: Boolean = true
|
||||
|
||||
fun addCallback(callback: AdaptiveSheetCallback) {
|
||||
callbacks.add(callback)
|
||||
}
|
||||
|
||||
fun removeCallback(callback: AdaptiveSheetCallback) {
|
||||
callbacks.remove(callback)
|
||||
}
|
||||
|
||||
class Bottom(
|
||||
private val delegate: BottomSheetBehavior<*>,
|
||||
) : AdaptiveSheetBehavior() {
|
||||
|
||||
override var state: Int
|
||||
get() = delegate.state
|
||||
set(value) {
|
||||
delegate.state = value
|
||||
}
|
||||
|
||||
override var isDraggable: Boolean
|
||||
get() = delegate.isDraggable
|
||||
set(value) {
|
||||
delegate.isDraggable = value
|
||||
}
|
||||
|
||||
override val isHideable: Boolean
|
||||
get() = delegate.isHideable
|
||||
|
||||
var isFitToContents: Boolean
|
||||
get() = delegate.isFitToContents
|
||||
set(value) {
|
||||
delegate.isFitToContents = value
|
||||
}
|
||||
|
||||
init {
|
||||
delegate.addBottomSheetCallback(
|
||||
object : BottomSheetCallback() {
|
||||
override fun onStateChanged(bottomSheet: View, newState: Int) {
|
||||
callbacks.forEach { it.onStateChanged(bottomSheet, newState) }
|
||||
}
|
||||
|
||||
override fun onSlide(bottomSheet: View, slideOffset: Float) {
|
||||
callbacks.forEach { it.onSlide(bottomSheet, slideOffset) }
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class Side(
|
||||
private val delegate: SideSheetBehavior<*>,
|
||||
) : AdaptiveSheetBehavior() {
|
||||
|
||||
override var state: Int
|
||||
get() = delegate.state
|
||||
set(value) {
|
||||
delegate.state = value
|
||||
}
|
||||
|
||||
override var isDraggable: Boolean
|
||||
get() = delegate.isDraggable
|
||||
set(value) {
|
||||
delegate.isDraggable = value
|
||||
}
|
||||
|
||||
init {
|
||||
delegate.addCallback(
|
||||
object : SideSheetCallback() {
|
||||
override fun onStateChanged(sheet: View, newState: Int) {
|
||||
callbacks.forEach { it.onStateChanged(sheet, newState) }
|
||||
}
|
||||
|
||||
override fun onSlide(sheet: View, slideOffset: Float) {
|
||||
callbacks.forEach { it.onSlide(sheet, slideOffset) }
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
const val STATE_EXPANDED = SideSheetBehavior.STATE_EXPANDED
|
||||
const val STATE_SETTLING = SideSheetBehavior.STATE_SETTLING
|
||||
const val STATE_DRAGGING = SideSheetBehavior.STATE_DRAGGING
|
||||
const val STATE_HIDDEN = SideSheetBehavior.STATE_HIDDEN
|
||||
|
||||
fun from(dialog: Dialog?): AdaptiveSheetBehavior? = when (dialog) {
|
||||
is BottomSheetDialog -> Bottom(dialog.behavior)
|
||||
is SideSheetDialog -> Side(dialog.behavior)
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun from(lp: CoordinatorLayout.LayoutParams): AdaptiveSheetBehavior? = when (val behavior = lp.behavior) {
|
||||
is BottomSheetBehavior<*> -> Bottom(behavior)
|
||||
is SideSheetBehavior<*> -> Side(behavior)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package org.koitharu.kotatsu.core.ui.sheet
|
||||
|
||||
import android.view.View
|
||||
|
||||
interface AdaptiveSheetCallback {
|
||||
|
||||
/**
|
||||
* Called when the sheet changes its state.
|
||||
*
|
||||
* @param sheet The sheet view.
|
||||
* @param newState The new state.
|
||||
*/
|
||||
fun onStateChanged(sheet: View, newState: Int)
|
||||
|
||||
/**
|
||||
* Called when the sheet is being dragged.
|
||||
*
|
||||
* @param sheet The sheet view.
|
||||
* @param slideOffset The new offset of this sheet.
|
||||
*/
|
||||
fun onSlide(sheet: View, slideOffset: Float) = Unit
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package org.koitharu.kotatsu.core.ui.sheet
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.WindowInsets
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.AttrRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
import androidx.core.content.withStyledAttributes
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.isGone
|
||||
import androidx.core.view.isVisible
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.util.ext.parents
|
||||
import org.koitharu.kotatsu.databinding.LayoutSheetHeaderAdaptiveBinding
|
||||
|
||||
class AdaptiveSheetHeaderBar @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
@AttrRes defStyleAttr: Int = 0,
|
||||
) : LinearLayout(context, attrs, defStyleAttr), AdaptiveSheetCallback {
|
||||
|
||||
private val binding = LayoutSheetHeaderAdaptiveBinding.inflate(LayoutInflater.from(context), this)
|
||||
private var sheetBehavior: AdaptiveSheetBehavior? = null
|
||||
|
||||
var title: CharSequence?
|
||||
get() = binding.textViewTitle.text
|
||||
set(value) {
|
||||
binding.textViewTitle.text = value
|
||||
}
|
||||
|
||||
val isExpanded: Boolean
|
||||
get() = binding.dragHandle.isGone
|
||||
|
||||
init {
|
||||
orientation = VERTICAL
|
||||
binding.buttonClose.setOnClickListener { dismissSheet() }
|
||||
context.withStyledAttributes(
|
||||
attrs,
|
||||
R.styleable.AdaptiveSheetHeaderBar, defStyleAttr,
|
||||
) {
|
||||
title = getText(R.styleable.AdaptiveSheetHeaderBar_title)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onAttachedToWindow() {
|
||||
super.onAttachedToWindow()
|
||||
dispatchInsets(ViewCompat.getRootWindowInsets(this))
|
||||
setBottomSheetBehavior(findParentSheetBehavior())
|
||||
}
|
||||
|
||||
override fun onDetachedFromWindow() {
|
||||
setBottomSheetBehavior(null)
|
||||
super.onDetachedFromWindow()
|
||||
}
|
||||
|
||||
override fun onApplyWindowInsets(insets: WindowInsets?): WindowInsets {
|
||||
dispatchInsets(if (insets != null) WindowInsetsCompat.toWindowInsetsCompat(insets) else null)
|
||||
return super.onApplyWindowInsets(insets)
|
||||
}
|
||||
|
||||
override fun onStateChanged(sheet: View, newState: Int) {
|
||||
|
||||
}
|
||||
|
||||
fun setTitle(@StringRes resId: Int) {
|
||||
binding.textViewTitle.setText(resId)
|
||||
}
|
||||
|
||||
private fun dispatchInsets(insets: WindowInsetsCompat?) {
|
||||
|
||||
}
|
||||
|
||||
private fun setBottomSheetBehavior(behavior: AdaptiveSheetBehavior?) {
|
||||
binding.dragHandle.isVisible = behavior is AdaptiveSheetBehavior.Bottom
|
||||
binding.layoutSidesheet.isVisible = behavior is AdaptiveSheetBehavior.Side
|
||||
sheetBehavior?.removeCallback(this)
|
||||
sheetBehavior = behavior
|
||||
behavior?.addCallback(this)
|
||||
}
|
||||
|
||||
private fun dismissSheet() {
|
||||
sheetBehavior?.state = AdaptiveSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
|
||||
private fun findParentSheetBehavior(): AdaptiveSheetBehavior? {
|
||||
for (p in parents) {
|
||||
val layoutParams = (p as? View)?.layoutParams
|
||||
if (layoutParams is CoordinatorLayout.LayoutParams) {
|
||||
AdaptiveSheetBehavior.from(layoutParams)?.let {
|
||||
return it
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package org.koitharu.kotatsu.core.ui.sheet
|
||||
|
||||
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.ComponentDialog
|
||||
import androidx.activity.OnBackPressedDispatcher
|
||||
import androidx.appcompat.app.AppCompatDialogFragment
|
||||
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.sidesheet.SideSheetDialog
|
||||
import org.koitharu.kotatsu.R
|
||||
import com.google.android.material.R as materialR
|
||||
|
||||
abstract class BaseAdaptiveSheet<B : ViewBinding> : AppCompatDialogFragment() {
|
||||
|
||||
private var waitingForDismissAllowingStateLoss = false
|
||||
|
||||
var viewBinding: B? = null
|
||||
private set
|
||||
|
||||
@Deprecated("", ReplaceWith("requireViewBinding()"))
|
||||
protected val binding: B
|
||||
get() = requireViewBinding()
|
||||
|
||||
protected val behavior: AdaptiveSheetBehavior?
|
||||
get() = AdaptiveSheetBehavior.from(dialog)
|
||||
|
||||
val isExpanded: Boolean
|
||||
get() = behavior?.state == AdaptiveSheetBehavior.STATE_EXPANDED
|
||||
|
||||
val onBackPressedDispatcher: OnBackPressedDispatcher
|
||||
get() = (requireDialog() as ComponentDialog).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()
|
||||
onViewBindingCreated(binding, savedInstanceState)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
viewBinding = null
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
val context = requireContext()
|
||||
return if (context.resources.getBoolean(R.bool.is_tablet)) {
|
||||
SideSheetDialog(context, theme)
|
||||
} else {
|
||||
BottomSheetDialog(context, theme)
|
||||
}
|
||||
}
|
||||
|
||||
fun addSheetCallback(callback: AdaptiveSheetCallback) {
|
||||
val b = behavior ?: return
|
||||
b.addCallback(callback)
|
||||
val rootView = dialog?.findViewById<View>(materialR.id.design_bottom_sheet)
|
||||
?: dialog?.findViewById(materialR.id.coordinator)
|
||||
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
|
||||
}
|
||||
if (b is AdaptiveSheetBehavior.Bottom) {
|
||||
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()."
|
||||
}
|
||||
|
||||
override fun dismiss() {
|
||||
if (!tryDismissWithAnimation(false)) {
|
||||
super.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun dismissAllowingStateLoss() {
|
||||
if (!tryDismissWithAnimation(true)) {
|
||||
super.dismissAllowingStateLoss()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to dismiss the dialog fragment with the bottom sheet animation. Returns true if possible,
|
||||
* false otherwise.
|
||||
*/
|
||||
private fun tryDismissWithAnimation(allowingStateLoss: Boolean): Boolean {
|
||||
val shouldDismissWithAnimation = when (val dialog = dialog) {
|
||||
is BottomSheetDialog -> dialog.dismissWithAnimation
|
||||
is SideSheetDialog -> dialog.isDismissWithSheetAnimationEnabled
|
||||
else -> false
|
||||
}
|
||||
val behavior = behavior ?: return false
|
||||
return if (shouldDismissWithAnimation && behavior.isHideable) {
|
||||
dismissWithAnimation(behavior, allowingStateLoss)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissWithAnimation(behavior: AdaptiveSheetBehavior, allowingStateLoss: Boolean) {
|
||||
waitingForDismissAllowingStateLoss = allowingStateLoss
|
||||
if (behavior.state == AdaptiveSheetBehavior.STATE_HIDDEN) {
|
||||
dismissAfterAnimation()
|
||||
} else {
|
||||
behavior.addCallback(SheetDismissCallback())
|
||||
behavior.state = AdaptiveSheetBehavior.STATE_HIDDEN
|
||||
}
|
||||
}
|
||||
|
||||
private fun dismissAfterAnimation() {
|
||||
if (waitingForDismissAllowingStateLoss) {
|
||||
super.dismissAllowingStateLoss()
|
||||
} else {
|
||||
super.dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private inner class SheetDismissCallback : AdaptiveSheetCallback {
|
||||
override fun onStateChanged(sheet: View, newState: Int) {
|
||||
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
|
||||
dismissAfterAnimation()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onSlide(sheet: View, slideOffset: Float) {}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import com.google.android.material.R as materialR
|
||||
|
||||
private const val THROTTLE_DELAY = 200L
|
||||
|
||||
@Deprecated("")
|
||||
class BottomSheetHeaderBar @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null,
|
||||
|
||||
@@ -18,11 +18,11 @@ import org.koitharu.kotatsu.browser.BrowserActivity
|
||||
import org.koitharu.kotatsu.core.os.ShortcutsUpdater
|
||||
import org.koitharu.kotatsu.core.util.ShareHelper
|
||||
import org.koitharu.kotatsu.details.ui.model.MangaBranch
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.mapNotNullToSet
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorBottomSheet
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
|
||||
import org.koitharu.kotatsu.search.ui.multi.MultiSearchActivity
|
||||
|
||||
class DetailsMenuProvider(
|
||||
@@ -63,7 +63,7 @@ class DetailsMenuProvider(
|
||||
|
||||
R.id.action_favourite -> {
|
||||
viewModel.manga.value?.let {
|
||||
FavouriteCategoriesBottomSheet.show(activity.supportFragmentManager, it)
|
||||
FavouriteCategoriesSheet.show(activity.supportFragmentManager, it)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class DetailsMenuProvider(
|
||||
|
||||
R.id.action_scrobbling -> {
|
||||
viewModel.manga.value?.let {
|
||||
ScrobblingSelectorBottomSheet.show(activity.supportFragmentManager, it, null)
|
||||
ScrobblingSelectorSheet.show(activity.supportFragmentManager, it, null)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ fun scrobblingInfoAD(
|
||||
{ layoutInflater, parent -> ItemScrobblingInfoBinding.inflate(layoutInflater, parent, false) },
|
||||
) {
|
||||
binding.root.setOnClickListener {
|
||||
ScrobblingInfoBottomSheet.show(fragmentManager, bindingAdapterPosition)
|
||||
ScrobblingInfoSheet.show(fragmentManager, bindingAdapterPosition)
|
||||
}
|
||||
|
||||
bind {
|
||||
|
||||
@@ -17,7 +17,7 @@ import androidx.fragment.app.activityViewModels
|
||||
import coil.ImageLoader
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ext.enqueueWith
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.core.util.ext.newImageRequest
|
||||
@@ -30,12 +30,12 @@ import org.koitharu.kotatsu.details.ui.DetailsViewModel
|
||||
import org.koitharu.kotatsu.image.ui.ImageActivity
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingInfo
|
||||
import org.koitharu.kotatsu.scrobbling.common.domain.model.ScrobblingStatus
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorBottomSheet
|
||||
import org.koitharu.kotatsu.scrobbling.common.ui.selector.ScrobblingSelectorSheet
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ScrobblingInfoBottomSheet :
|
||||
BaseBottomSheet<SheetScrobblingBinding>(),
|
||||
class ScrobblingInfoSheet :
|
||||
BaseAdaptiveSheet<SheetScrobblingBinding>(),
|
||||
AdapterView.OnItemSelectedListener,
|
||||
RatingBar.OnRatingBarChangeListener,
|
||||
View.OnClickListener,
|
||||
@@ -74,7 +74,7 @@ class ScrobblingInfoBottomSheet :
|
||||
|
||||
menu = PopupMenu(binding.root.context, binding.buttonMenu).apply {
|
||||
inflate(R.menu.opt_scrobbling)
|
||||
setOnMenuItemClickListener(this@ScrobblingInfoBottomSheet)
|
||||
setOnMenuItemClickListener(this@ScrobblingInfoSheet)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ class ScrobblingInfoBottomSheet :
|
||||
R.id.action_edit -> {
|
||||
val manga = viewModel.manga.value ?: return false
|
||||
val scrobblerService = viewModel.scrobblingInfo.value.getOrNull(scrobblerIndex)?.scrobbler
|
||||
ScrobblingSelectorBottomSheet.show(parentFragmentManager, manga, scrobblerService)
|
||||
ScrobblingSelectorSheet.show(parentFragmentManager, manga, scrobblerService)
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
@@ -164,7 +164,7 @@ class ScrobblingInfoBottomSheet :
|
||||
private const val TAG = "ScrobblingInfoBottomSheet"
|
||||
private const val ARG_INDEX = "index"
|
||||
|
||||
fun show(fm: FragmentManager, index: Int) = ScrobblingInfoBottomSheet().withArgs(1) {
|
||||
fun show(fm: FragmentManager, index: Int) = ScrobblingInfoSheet().withArgs(1) {
|
||||
putInt(ARG_INDEX, index)
|
||||
}.show(fm, TAG)
|
||||
}
|
||||
@@ -2,34 +2,29 @@ package org.koitharu.kotatsu.favourites.ui.categories.select
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.MenuItem
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
import org.koitharu.kotatsu.core.util.ext.withArgs
|
||||
import org.koitharu.kotatsu.databinding.SheetFavoriteCategoriesBinding
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.adapter.MangaCategoriesAdapter
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
|
||||
@AndroidEntryPoint
|
||||
class FavouriteCategoriesBottomSheet :
|
||||
BaseBottomSheet<SheetFavoriteCategoriesBinding>(),
|
||||
OnListItemClickListener<MangaCategoryItem>,
|
||||
View.OnClickListener,
|
||||
Toolbar.OnMenuItemClickListener {
|
||||
class FavouriteCategoriesSheet :
|
||||
BaseAdaptiveSheet<SheetFavoriteCategoriesBinding>(),
|
||||
OnListItemClickListener<MangaCategoryItem> {
|
||||
|
||||
private val viewModel: MangaCategoriesViewModel by viewModels()
|
||||
|
||||
@@ -40,13 +35,13 @@ class FavouriteCategoriesBottomSheet :
|
||||
container: ViewGroup?,
|
||||
) = SheetFavoriteCategoriesBinding.inflate(inflater, container, false)
|
||||
|
||||
override fun onViewBindingCreated(binding: SheetFavoriteCategoriesBinding, savedInstanceState: Bundle?) {
|
||||
override fun onViewBindingCreated(
|
||||
binding: SheetFavoriteCategoriesBinding,
|
||||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
adapter = MangaCategoriesAdapter(this)
|
||||
binding.recyclerViewCategories.adapter = adapter
|
||||
binding.buttonDone.setOnClickListener(this)
|
||||
binding.headerBar.toolbar.setOnMenuItemClickListener(this)
|
||||
|
||||
viewModel.content.observe(viewLifecycleOwner, this::onContentChanged)
|
||||
viewModel.onError.observeEvent(viewLifecycleOwner, ::onError)
|
||||
}
|
||||
@@ -56,25 +51,11 @@ class FavouriteCategoriesBottomSheet :
|
||||
super.onDestroyView()
|
||||
}
|
||||
|
||||
override fun onClick(v: View) {
|
||||
when (v.id) {
|
||||
R.id.button_done -> dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
when (item.itemId) {
|
||||
R.id.action_create -> startActivity(FavouritesCategoryEditActivity.newIntent(requireContext()))
|
||||
else -> return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
override fun onItemClick(item: MangaCategoryItem, view: View) {
|
||||
viewModel.setChecked(item.id, !item.isChecked)
|
||||
}
|
||||
|
||||
private fun onContentChanged(categories: List<MangaCategoryItem>) {
|
||||
private fun onContentChanged(categories: List<ListModel>) {
|
||||
adapter?.items = categories
|
||||
}
|
||||
|
||||
@@ -89,11 +70,17 @@ class FavouriteCategoriesBottomSheet :
|
||||
|
||||
fun show(fm: FragmentManager, manga: Manga) = Companion.show(fm, listOf(manga))
|
||||
|
||||
fun show(fm: FragmentManager, manga: Collection<Manga>) = FavouriteCategoriesBottomSheet().withArgs(1) {
|
||||
putParcelableArrayList(
|
||||
KEY_MANGA_LIST,
|
||||
manga.mapTo(ArrayList(manga.size)) { ParcelableManga(it, withChapters = false) },
|
||||
)
|
||||
}.show(fm, TAG)
|
||||
fun show(fm: FragmentManager, manga: Collection<Manga>) =
|
||||
FavouriteCategoriesSheet().withArgs(1) {
|
||||
putParcelableArrayList(
|
||||
KEY_MANGA_LIST,
|
||||
manga.mapTo(ArrayList(manga.size)) {
|
||||
ParcelableManga(
|
||||
it,
|
||||
withChapters = false,
|
||||
)
|
||||
},
|
||||
)
|
||||
}.show(fm, TAG)
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.SharingStarted
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.stateIn
|
||||
import kotlinx.coroutines.plus
|
||||
@@ -12,8 +13,10 @@ import org.koitharu.kotatsu.core.model.ids
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.ui.BaseViewModel
|
||||
import org.koitharu.kotatsu.favourites.domain.FavouritesRepository
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet.Companion.KEY_MANGA_LIST
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet.Companion.KEY_MANGA_LIST
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
import javax.inject.Inject
|
||||
|
||||
@HiltViewModel
|
||||
@@ -23,17 +26,21 @@ class MangaCategoriesViewModel @Inject constructor(
|
||||
) : BaseViewModel() {
|
||||
|
||||
private val manga = requireNotNull(savedStateHandle.get<List<ParcelableManga>>(KEY_MANGA_LIST)).map { it.manga }
|
||||
private val header = CategoriesHeaderItem()
|
||||
|
||||
val content = combine(
|
||||
val content: StateFlow<List<ListModel>> = combine(
|
||||
favouritesRepository.observeCategories(),
|
||||
observeCategoriesIds(),
|
||||
) { all, checked ->
|
||||
all.map {
|
||||
MangaCategoryItem(
|
||||
id = it.id,
|
||||
name = it.title,
|
||||
isChecked = it.id in checked,
|
||||
)
|
||||
buildList(all.size + 1) {
|
||||
add(header)
|
||||
all.mapTo(this) {
|
||||
MangaCategoryItem(
|
||||
id = it.id,
|
||||
name = it.title,
|
||||
isChecked = it.id in checked,
|
||||
)
|
||||
}
|
||||
}
|
||||
}.stateIn(viewModelScope + Dispatchers.Default, SharingStarted.Eagerly, emptyList())
|
||||
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
|
||||
|
||||
import android.view.View
|
||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.databinding.ItemCategoriesHeaderBinding
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.FavouriteCategoriesActivity
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.edit.FavouritesCategoryEditActivity
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
fun categoriesHeaderAD() = adapterDelegateViewBinding<CategoriesHeaderItem, ListModel, ItemCategoriesHeaderBinding>(
|
||||
{ inflater, parent -> ItemCategoriesHeaderBinding.inflate(inflater, parent, false) },
|
||||
) {
|
||||
|
||||
val onClickListener = View.OnClickListener { v ->
|
||||
val intent = when (v.id) {
|
||||
R.id.button_create -> FavouritesCategoryEditActivity.newIntent(v.context)
|
||||
R.id.button_manage -> FavouriteCategoriesActivity.newIntent(v.context)
|
||||
else -> return@OnClickListener
|
||||
}
|
||||
v.context.startActivity(intent)
|
||||
}
|
||||
|
||||
binding.buttonCreate.setOnClickListener(onClickListener)
|
||||
binding.buttonManage.setOnClickListener(onClickListener)
|
||||
}
|
||||
@@ -3,32 +3,39 @@ package org.koitharu.kotatsu.favourites.ui.categories.select.adapter
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.CategoriesHeaderItem
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class MangaCategoriesAdapter(
|
||||
clickListener: OnListItemClickListener<MangaCategoryItem>
|
||||
) : AsyncListDifferDelegationAdapter<MangaCategoryItem>(DiffCallback()) {
|
||||
clickListener: OnListItemClickListener<MangaCategoryItem>,
|
||||
) : AsyncListDifferDelegationAdapter<ListModel>(DiffCallback()) {
|
||||
|
||||
init {
|
||||
delegatesManager.addDelegate(mangaCategoryAD(clickListener))
|
||||
.addDelegate(categoriesHeaderAD())
|
||||
}
|
||||
|
||||
private class DiffCallback : DiffUtil.ItemCallback<MangaCategoryItem>() {
|
||||
private class DiffCallback : DiffUtil.ItemCallback<ListModel>() {
|
||||
override fun areItemsTheSame(
|
||||
oldItem: MangaCategoryItem,
|
||||
newItem: MangaCategoryItem
|
||||
): Boolean = oldItem.id == newItem.id
|
||||
oldItem: ListModel,
|
||||
newItem: ListModel,
|
||||
): Boolean = when {
|
||||
oldItem is MangaCategoryItem && newItem is MangaCategoryItem -> oldItem.id == newItem.id
|
||||
oldItem is CategoriesHeaderItem && newItem is CategoriesHeaderItem -> oldItem == newItem
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun areContentsTheSame(
|
||||
oldItem: MangaCategoryItem,
|
||||
newItem: MangaCategoryItem
|
||||
oldItem: ListModel,
|
||||
newItem: ListModel,
|
||||
): Boolean = oldItem == newItem
|
||||
|
||||
override fun getChangePayload(
|
||||
oldItem: MangaCategoryItem,
|
||||
newItem: MangaCategoryItem
|
||||
oldItem: ListModel,
|
||||
newItem: ListModel,
|
||||
): Any? {
|
||||
if (oldItem.isChecked != newItem.isChecked) {
|
||||
if (oldItem is MangaCategoryItem && newItem is MangaCategoryItem && oldItem.isChecked != newItem.isChecked) {
|
||||
return newItem.isChecked
|
||||
}
|
||||
return super.getChangePayload(oldItem, newItem)
|
||||
|
||||
@@ -4,10 +4,11 @@ import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.databinding.ItemCheckableNewBinding
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.model.MangaCategoryItem
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
fun mangaCategoryAD(
|
||||
clickListener: OnListItemClickListener<MangaCategoryItem>
|
||||
) = adapterDelegateViewBinding<MangaCategoryItem, MangaCategoryItem, ItemCheckableNewBinding>(
|
||||
clickListener: OnListItemClickListener<MangaCategoryItem>,
|
||||
) = adapterDelegateViewBinding<MangaCategoryItem, ListModel, ItemCheckableNewBinding>(
|
||||
{ inflater, parent -> ItemCheckableNewBinding.inflate(inflater, parent, false) },
|
||||
) {
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select.model
|
||||
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
class CategoriesHeaderItem : ListModel {
|
||||
|
||||
override fun equals(other: Any?): Boolean = other?.javaClass == CategoriesHeaderItem::class.java
|
||||
}
|
||||
@@ -1,7 +1,9 @@
|
||||
package org.koitharu.kotatsu.favourites.ui.categories.select.model
|
||||
|
||||
import org.koitharu.kotatsu.list.ui.model.ListModel
|
||||
|
||||
data class MangaCategoryItem(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val isChecked: Boolean
|
||||
)
|
||||
val isChecked: Boolean,
|
||||
) : ListModel
|
||||
|
||||
@@ -11,7 +11,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.ListMode
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ext.setValueRounded
|
||||
import org.koitharu.kotatsu.core.util.progress.IntPercentLabelFormatter
|
||||
import org.koitharu.kotatsu.databinding.DialogListModeBinding
|
||||
@@ -19,7 +19,7 @@ import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ListModeBottomSheet :
|
||||
BaseBottomSheet<DialogListModeBinding>(),
|
||||
BaseAdaptiveSheet<DialogListModeBinding>(),
|
||||
Slider.OnChangeListener,
|
||||
MaterialButtonToggleGroup.OnButtonCheckedListener {
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
|
||||
import org.koitharu.kotatsu.databinding.FragmentListBinding
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet
|
||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter
|
||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListAdapter.Companion.ITEM_TYPE_MANGA_GRID
|
||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
||||
@@ -296,7 +296,7 @@ abstract class MangaListFragment :
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavouriteCategoriesBottomSheet.show(childFragmentManager, selectedItems)
|
||||
FavouriteCategoriesSheet.show(childFragmentManager, selectedItems)
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableMangaChapters
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.RecyclerViewScrollCallback
|
||||
import org.koitharu.kotatsu.core.util.ext.getParcelableCompat
|
||||
import org.koitharu.kotatsu.core.util.ext.withArgs
|
||||
@@ -23,7 +23,7 @@ import javax.inject.Inject
|
||||
import kotlin.math.roundToInt
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ChaptersBottomSheet : BaseBottomSheet<SheetChaptersBinding>(), OnListItemClickListener<ChapterListItem> {
|
||||
class ChaptersSheet : BaseAdaptiveSheet<SheetChaptersBinding>(), OnListItemClickListener<ChapterListItem> {
|
||||
|
||||
@Inject
|
||||
lateinit var settings: AppSettings
|
||||
@@ -83,7 +83,7 @@ class ChaptersBottomSheet : BaseBottomSheet<SheetChaptersBinding>(), OnListItemC
|
||||
fm: FragmentManager,
|
||||
chapters: List<MangaChapter>,
|
||||
currentId: Long,
|
||||
) = ChaptersBottomSheet().withArgs(2) {
|
||||
) = ChaptersSheet().withArgs(2) {
|
||||
putParcelable(ARG_CHAPTERS, ParcelableMangaChapters(chapters))
|
||||
putLong(ARG_CURRENT_ID, currentId)
|
||||
}.show(fm, TAG)
|
||||
@@ -52,7 +52,7 @@ import org.koitharu.kotatsu.core.util.ext.zipWithPrevious
|
||||
import org.koitharu.kotatsu.databinding.ActivityReaderBinding
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
import org.koitharu.kotatsu.reader.ui.config.ReaderConfigBottomSheet
|
||||
import org.koitharu.kotatsu.reader.ui.config.ReaderConfigSheet
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderPage
|
||||
import org.koitharu.kotatsu.reader.ui.pager.ReaderUiState
|
||||
import org.koitharu.kotatsu.reader.ui.thumbnails.OnPageSelectListener
|
||||
@@ -64,10 +64,10 @@ import javax.inject.Inject
|
||||
@AndroidEntryPoint
|
||||
class ReaderActivity :
|
||||
BaseFullscreenActivity<ActivityReaderBinding>(),
|
||||
ChaptersBottomSheet.OnChapterChangeListener,
|
||||
ChaptersSheet.OnChapterChangeListener,
|
||||
GridTouchHelper.OnGridTouchListener,
|
||||
OnPageSelectListener,
|
||||
ReaderConfigBottomSheet.Callback,
|
||||
ReaderConfigSheet.Callback,
|
||||
ReaderControlDelegate.OnInteractionListener,
|
||||
OnApplyWindowInsetsListener,
|
||||
IdlingDetector.Callback {
|
||||
@@ -179,7 +179,7 @@ class ReaderActivity :
|
||||
}
|
||||
|
||||
R.id.action_chapters -> {
|
||||
ChaptersBottomSheet.show(
|
||||
ChaptersSheet.show(
|
||||
supportFragmentManager,
|
||||
viewModel.manga?.chapters.orEmpty(),
|
||||
viewModel.getCurrentState()?.chapterId ?: 0L,
|
||||
@@ -207,7 +207,7 @@ class ReaderActivity :
|
||||
R.id.action_options -> {
|
||||
viewModel.saveCurrentState(readerManager.currentReader?.getCurrentState())
|
||||
val currentMode = readerManager.currentMode ?: return false
|
||||
ReaderConfigBottomSheet.show(supportFragmentManager, currentMode)
|
||||
ReaderConfigSheet.show(supportFragmentManager, currentMode)
|
||||
}
|
||||
|
||||
else -> return super.onOptionsItemSelected(item)
|
||||
|
||||
@@ -23,7 +23,7 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.prefs.ReaderMode
|
||||
import org.koitharu.kotatsu.core.prefs.observeAsStateFlow
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ScreenOrientationHelper
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.viewLifecycleScope
|
||||
@@ -36,8 +36,8 @@ import org.koitharu.kotatsu.settings.SettingsActivity
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ReaderConfigBottomSheet :
|
||||
BaseBottomSheet<SheetReaderConfigBinding>(),
|
||||
class ReaderConfigSheet :
|
||||
BaseAdaptiveSheet<SheetReaderConfigBinding>(),
|
||||
ActivityResultCallback<Uri?>,
|
||||
View.OnClickListener,
|
||||
MaterialButtonToggleGroup.OnButtonCheckedListener,
|
||||
@@ -59,11 +59,17 @@ class ReaderConfigBottomSheet :
|
||||
?: ReaderMode.STANDARD
|
||||
}
|
||||
|
||||
override fun onCreateViewBinding(inflater: LayoutInflater, container: ViewGroup?): SheetReaderConfigBinding {
|
||||
override fun onCreateViewBinding(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
): SheetReaderConfigBinding {
|
||||
return SheetReaderConfigBinding.inflate(inflater, container, false)
|
||||
}
|
||||
|
||||
override fun onViewBindingCreated(binding: SheetReaderConfigBinding, savedInstanceState: Bundle?) {
|
||||
override fun onViewBindingCreated(
|
||||
binding: SheetReaderConfigBinding,
|
||||
savedInstanceState: Bundle?,
|
||||
) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
observeScreenOrientation()
|
||||
binding.buttonStandard.isChecked = mode == ReaderMode.STANDARD
|
||||
@@ -127,7 +133,11 @@ class ReaderConfigBottomSheet :
|
||||
}
|
||||
}
|
||||
|
||||
override fun onButtonChecked(group: MaterialButtonToggleGroup?, checkedId: Int, isChecked: Boolean) {
|
||||
override fun onButtonChecked(
|
||||
group: MaterialButtonToggleGroup?,
|
||||
checkedId: Int,
|
||||
isChecked: Boolean,
|
||||
) {
|
||||
if (!isChecked) {
|
||||
return
|
||||
}
|
||||
@@ -180,7 +190,7 @@ class ReaderConfigBottomSheet :
|
||||
private const val TAG = "ReaderConfigBottomSheet"
|
||||
private const val ARG_MODE = "mode"
|
||||
|
||||
fun show(fm: FragmentManager, mode: ReaderMode) = ReaderConfigBottomSheet().withArgs(1) {
|
||||
fun show(fm: FragmentManager, mode: ReaderMode) = ReaderConfigSheet().withArgs(1) {
|
||||
putInt(ARG_MODE, mode.id)
|
||||
}.show(fm, TAG)
|
||||
}
|
||||
@@ -14,12 +14,13 @@ import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.exceptions.resolve.SnackbarErrorObserver
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.prefs.AppSettings
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.list.BoundsScrollListener
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.ScrollListenerInvalidationObserver
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.SpacingItemDecoration
|
||||
import org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetBehavior
|
||||
import org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetCallback
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.core.util.ext.observeEvent
|
||||
import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
|
||||
@@ -31,14 +32,13 @@ import org.koitharu.kotatsu.reader.ui.ReaderActivity
|
||||
import org.koitharu.kotatsu.reader.ui.ReaderState
|
||||
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.PageThumbnailAdapter
|
||||
import org.koitharu.kotatsu.reader.ui.thumbnails.adapter.TargetScrollObserver
|
||||
import org.koitharu.kotatsu.util.LoggingAdapterDataObserver
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class PagesThumbnailsSheet :
|
||||
BaseBottomSheet<SheetPagesBinding>(),
|
||||
OnListItemClickListener<PageThumbnail>,
|
||||
BottomSheetHeaderBar.OnExpansionChangeListener {
|
||||
BaseAdaptiveSheet<SheetPagesBinding>(),
|
||||
AdaptiveSheetCallback,
|
||||
OnListItemClickListener<PageThumbnail> {
|
||||
|
||||
private val viewModel by viewModels<PagesThumbnailsViewModel>()
|
||||
|
||||
@@ -64,11 +64,6 @@ class PagesThumbnailsSheet :
|
||||
override fun onViewBindingCreated(binding: SheetPagesBinding, savedInstanceState: Bundle?) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
spanResolver = MangaListSpanResolver(binding.root.resources)
|
||||
with(binding.headerBar) {
|
||||
title = viewModel.title
|
||||
subtitle = null
|
||||
addOnExpansionChangeListener(this@PagesThumbnailsSheet)
|
||||
}
|
||||
thumbnailsAdapter = PageThumbnailAdapter(
|
||||
coil = coil,
|
||||
lifecycleOwner = viewLifecycleOwner,
|
||||
@@ -87,14 +82,11 @@ class PagesThumbnailsSheet :
|
||||
ScrollListenerInvalidationObserver(this, checkNotNull(scrollListener)),
|
||||
)
|
||||
thumbnailsAdapter?.registerAdapterDataObserver(TargetScrollObserver(this))
|
||||
thumbnailsAdapter?.registerAdapterDataObserver(LoggingAdapterDataObserver("THUMB"))
|
||||
}
|
||||
viewModel.thumbnails.observe(viewLifecycleOwner) {
|
||||
thumbnailsAdapter?.setItems(it, listCommitCallback)
|
||||
}
|
||||
viewModel.branch.observe(viewLifecycleOwner) {
|
||||
onExpansionStateChanged(binding.headerBar, binding.headerBar.isExpanded)
|
||||
}
|
||||
viewModel.branch.observe(viewLifecycleOwner, ::updateTitle)
|
||||
viewModel.onError.observeEvent(viewLifecycleOwner, SnackbarErrorObserver(binding.recyclerView, this))
|
||||
}
|
||||
|
||||
@@ -118,13 +110,17 @@ class PagesThumbnailsSheet :
|
||||
dismiss()
|
||||
}
|
||||
|
||||
override fun onExpansionStateChanged(headerBar: BottomSheetHeaderBar, isExpanded: Boolean) {
|
||||
if (isExpanded) {
|
||||
headerBar.subtitle = viewModel.branch.value
|
||||
override fun onStateChanged(sheet: View, newState: Int) {
|
||||
viewBinding?.recyclerView?.isFastScrollerEnabled = newState == AdaptiveSheetBehavior.STATE_EXPANDED
|
||||
}
|
||||
|
||||
private fun updateTitle(branch: String?) {
|
||||
val mangaName = viewModel.manga.title
|
||||
viewBinding?.headerBar?.title = if (branch != null) {
|
||||
getString(R.string.manga_branch_title_template, mangaName, branch)
|
||||
} else {
|
||||
headerBar.subtitle = null
|
||||
mangaName
|
||||
}
|
||||
viewBinding?.recyclerView?.isFastScrollerEnabled = isExpanded
|
||||
}
|
||||
|
||||
private inner class ScrollListener : BoundsScrollListener(3, 3) {
|
||||
|
||||
@@ -42,7 +42,6 @@ class PagesThumbnailsViewModel @Inject constructor(
|
||||
|
||||
val thumbnails = MutableStateFlow<List<ListModel>>(emptyList())
|
||||
val branch = MutableStateFlow<String?>(null)
|
||||
val title = manga.title
|
||||
|
||||
init {
|
||||
loadingJob = launchJob(Dispatchers.Default) {
|
||||
|
||||
@@ -16,9 +16,9 @@ import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.parcelable.ParcelableManga
|
||||
import org.koitharu.kotatsu.core.parser.MangaIntent
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.list.PaginationScrollListener
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.ui.util.CollapseActionViewCallback
|
||||
import org.koitharu.kotatsu.core.util.ext.firstVisibleItemPosition
|
||||
import org.koitharu.kotatsu.core.util.ext.getDisplayMessage
|
||||
@@ -35,8 +35,8 @@ import org.koitharu.kotatsu.scrobbling.common.ui.selector.adapter.ScrobblerSelec
|
||||
import javax.inject.Inject
|
||||
|
||||
@AndroidEntryPoint
|
||||
class ScrobblingSelectorBottomSheet :
|
||||
BaseBottomSheet<SheetScrobblingSelectorBinding>(),
|
||||
class ScrobblingSelectorSheet :
|
||||
BaseAdaptiveSheet<SheetScrobblingSelectorBinding>(),
|
||||
OnListItemClickListener<ScrobblerManga>,
|
||||
PaginationScrollListener.Callback,
|
||||
View.OnClickListener,
|
||||
@@ -63,7 +63,7 @@ class ScrobblingSelectorBottomSheet :
|
||||
with(binding.recyclerView) {
|
||||
adapter = listAdapter
|
||||
addItemDecoration(decoration)
|
||||
addOnScrollListener(PaginationScrollListener(4, this@ScrobblingSelectorBottomSheet))
|
||||
addOnScrollListener(PaginationScrollListener(4, this@ScrobblingSelectorSheet))
|
||||
}
|
||||
binding.buttonDone.setOnClickListener(this)
|
||||
initOptionsMenu()
|
||||
@@ -209,7 +209,7 @@ class ScrobblingSelectorBottomSheet :
|
||||
private const val ARG_SCROBBLER = "scrobbler"
|
||||
|
||||
fun show(fm: FragmentManager, manga: Manga, scrobblerService: ScrobblerService?) =
|
||||
ScrobblingSelectorBottomSheet().withArgs(2) {
|
||||
ScrobblingSelectorSheet().withArgs(2) {
|
||||
putParcelable(MangaIntent.KEY_MANGA, ParcelableManga(manga, withChapters = false))
|
||||
if (scrobblerService != null) {
|
||||
putInt(ARG_SCROBBLER, scrobblerService.id)
|
||||
@@ -27,7 +27,7 @@ import org.koitharu.kotatsu.core.util.ext.scaleUpActivityOptionsOf
|
||||
import org.koitharu.kotatsu.databinding.ActivitySearchMultiBinding
|
||||
import org.koitharu.kotatsu.details.ui.DetailsActivity
|
||||
import org.koitharu.kotatsu.download.ui.worker.DownloadStartedObserver
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet
|
||||
import org.koitharu.kotatsu.list.ui.ItemSizeResolver
|
||||
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
|
||||
import org.koitharu.kotatsu.list.ui.adapter.MangaListListener
|
||||
@@ -159,7 +159,7 @@ class MultiSearchActivity :
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavouriteCategoriesBottomSheet.show(supportFragmentManager, collectSelectedItems())
|
||||
FavouriteCategoriesSheet.show(supportFragmentManager, collectSelectedItems())
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -4,22 +4,20 @@ import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.fragment.app.viewModels
|
||||
import dagger.hilt.android.AndroidEntryPoint
|
||||
import org.koitharu.kotatsu.R
|
||||
import org.koitharu.kotatsu.core.model.FavouriteCategory
|
||||
import org.koitharu.kotatsu.core.ui.BaseBottomSheet
|
||||
import org.koitharu.kotatsu.core.ui.list.OnListItemClickListener
|
||||
import org.koitharu.kotatsu.core.ui.sheet.BaseAdaptiveSheet
|
||||
import org.koitharu.kotatsu.core.util.ext.observe
|
||||
import org.koitharu.kotatsu.databinding.SheetBaseBinding
|
||||
|
||||
@AndroidEntryPoint
|
||||
class TrackerCategoriesConfigSheet :
|
||||
BaseBottomSheet<SheetBaseBinding>(),
|
||||
OnListItemClickListener<FavouriteCategory>,
|
||||
View.OnClickListener {
|
||||
BaseAdaptiveSheet<SheetBaseBinding>(),
|
||||
OnListItemClickListener<FavouriteCategory> {
|
||||
|
||||
private val viewModel by viewModels<TrackerCategoriesConfigViewModel>()
|
||||
|
||||
@@ -30,8 +28,6 @@ class TrackerCategoriesConfigSheet :
|
||||
override fun onViewBindingCreated(binding: SheetBaseBinding, savedInstanceState: Bundle?) {
|
||||
super.onViewBindingCreated(binding, savedInstanceState)
|
||||
binding.headerBar.setTitle(R.string.favourites_categories)
|
||||
binding.buttonDone.isVisible = true
|
||||
binding.buttonDone.setOnClickListener(this)
|
||||
val adapter = TrackerCategoriesConfigAdapter(this)
|
||||
binding.recyclerView.adapter = adapter
|
||||
|
||||
@@ -42,10 +38,6 @@ class TrackerCategoriesConfigSheet :
|
||||
viewModel.toggleItem(item)
|
||||
}
|
||||
|
||||
override fun onClick(v: View?) {
|
||||
dismiss()
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private const val TAG = "TrackerCategoriesConfigSheet"
|
||||
|
||||
@@ -12,7 +12,7 @@ import org.koitharu.kotatsu.core.ui.list.SectionedSelectionController
|
||||
import org.koitharu.kotatsu.core.ui.list.decor.AbstractSelectionItemDecoration
|
||||
import org.koitharu.kotatsu.core.util.ShareHelper
|
||||
import org.koitharu.kotatsu.core.util.ext.invalidateNestedItemDecorations
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesBottomSheet
|
||||
import org.koitharu.kotatsu.favourites.ui.categories.select.FavouriteCategoriesSheet
|
||||
import org.koitharu.kotatsu.list.ui.MangaSelectionDecoration
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.util.flattenTo
|
||||
@@ -63,7 +63,7 @@ class ShelfSelectionCallback(
|
||||
}
|
||||
|
||||
R.id.action_favourite -> {
|
||||
FavouriteCategoriesBottomSheet.show(fragmentManager, collectSelectedItems(controller))
|
||||
FavouriteCategoriesSheet.show(fragmentManager, collectSelectedItems(controller))
|
||||
mode.finish()
|
||||
true
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
android:animateLayoutChanges="true"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -28,7 +28,6 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="@dimen/margin_normal"
|
||||
android:layout_marginTop="@dimen/margin_normal"
|
||||
android:text="@string/list_mode"
|
||||
android:textAppearance="?textAppearanceTitleSmall" />
|
||||
|
||||
|
||||
34
app/src/main/res/layout/item_categories_header.xml
Normal file
34
app/src/main/res/layout/item_categories_header.xml
Normal file
@@ -0,0 +1,34 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="horizontal"
|
||||
android:paddingHorizontal="12dp"
|
||||
android:paddingVertical="8dp"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_create"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/create_category"
|
||||
app:icon="@drawable/ic_add" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_manage"
|
||||
style="@style/Widget.Material3.Button.OutlinedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:text="@string/manage"
|
||||
app:icon="@drawable/ic_edit" />
|
||||
|
||||
</LinearLayout>
|
||||
52
app/src/main/res/layout/layout_sheet_header_adaptive.xml
Normal file
52
app/src/main/res/layout/layout_sheet_header_adaptive.xml
Normal file
@@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<merge
|
||||
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:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:orientation="vertical"
|
||||
tools:parentTag="android.widget.LinearLayout">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:id="@+id/dragHandle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/layout_sidesheet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal"
|
||||
android:paddingVertical="8dp"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_weight="1"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?textAppearanceBodyLarge"
|
||||
tools:text="@string/filter" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/button_close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:padding="16dp"
|
||||
app:srcCompat="?actionModeCloseDrawable"
|
||||
app:tint="?colorControlActivated" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</merge>
|
||||
@@ -7,23 +7,10 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_done"
|
||||
style="@style/Widget.Material3.Button.UnelevatedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginHorizontal="@dimen/toolbar_button_margin"
|
||||
android:text="@string/done"
|
||||
android:visibility="gone"
|
||||
tools:visibility="visible" />
|
||||
|
||||
</org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar>
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
@@ -31,6 +18,8 @@
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:scrollIndicators="top"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/item_checkable_new" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -19,6 +19,7 @@
|
||||
android:layout_height="match_parent"
|
||||
android:layout_below="@id/headerBar"
|
||||
android:orientation="vertical"
|
||||
android:scrollIndicators="top"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
tools:listitem="@layout/item_chapter" />
|
||||
|
||||
@@ -7,33 +7,24 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:menu="@menu/opt_categories_bs"
|
||||
app:title="@string/add_to_favourites">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_done"
|
||||
style="@style/Widget.Material3.Button.UnelevatedButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="end"
|
||||
android:layout_marginHorizontal="@dimen/toolbar_button_margin"
|
||||
android:text="@string/done" />
|
||||
|
||||
</org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar>
|
||||
app:layout_scrollFlags="noScroll"
|
||||
app:title="@string/add_to_favourites" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView_categories"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="vertical"
|
||||
android:overScrollMode="never"
|
||||
android:paddingVertical="@dimen/list_spacing"
|
||||
android:paddingBottom="@dimen/list_spacing"
|
||||
android:scrollIndicators="top"
|
||||
android:scrollbars="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:ignore="UnusedAttribute"
|
||||
tools:listitem="@layout/item_checkable_new" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
@@ -22,11 +22,13 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:clipToPadding="false"
|
||||
android:padding="@dimen/grid_spacing"
|
||||
android:scrollIndicators="top"
|
||||
app:bubbleSize="small"
|
||||
app:layoutManager="androidx.recyclerview.widget.GridLayoutManager"
|
||||
app:spanCount="3"
|
||||
app:trackColor="?attr/colorOutline"
|
||||
tools:listitem="@layout/item_page_thumb" />
|
||||
tools:listitem="@layout/item_page_thumb"
|
||||
tools:targetApi="m" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.koitharu.kotatsu.core.ui.widgets.BottomSheetHeaderBar
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
@@ -15,7 +15,8 @@
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:scrollIndicators="top">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -11,13 +11,14 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="16dp">
|
||||
|
||||
<com.google.android.material.bottomsheet.BottomSheetDragHandleView
|
||||
android:id="@+id/dragHandle"
|
||||
<org.koitharu.kotatsu.core.ui.sheet.AdaptiveSheetHeaderBar
|
||||
android:id="@+id/headerBar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:title="@string/tracking" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/imageView_cover"
|
||||
@@ -30,7 +31,7 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_bias="0"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dragHandle"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerBar"
|
||||
app:layout_constraintWidth_percent="0.3"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover"
|
||||
tools:background="@tools:sample/backgrounds/scenic"
|
||||
@@ -40,14 +41,14 @@
|
||||
android:id="@+id/imageView_logo"
|
||||
android:layout_width="32dp"
|
||||
android:layout_height="32dp"
|
||||
android:padding="4dp"
|
||||
android:layout_margin="@dimen/card_indicator_offset"
|
||||
android:background="@drawable/bg_badge_accent"
|
||||
android:padding="4dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/imageView_cover"
|
||||
app:layout_constraintEnd_toEndOf="@id/imageView_cover"
|
||||
app:tint="?attr/colorOnSecondary"
|
||||
tools:ignore="ContentDescription"
|
||||
tools:src="@drawable/ic_shikimori"
|
||||
app:tint="?attr/colorOnSecondary" />
|
||||
tools:src="@drawable/ic_shikimori" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/textView_title"
|
||||
@@ -60,7 +61,7 @@
|
||||
android:textAppearance="?attr/textAppearanceHeadlineSmall"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_menu"
|
||||
app:layout_constraintStart_toEndOf="@id/imageView_cover"
|
||||
app:layout_constraintTop_toBottomOf="@id/dragHandle"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerBar"
|
||||
tools:text="@tools:sample/lorem[9]" />
|
||||
|
||||
<ImageButton
|
||||
@@ -72,7 +73,7 @@
|
||||
android:background="?selectableItemBackgroundBorderless"
|
||||
android:contentDescription="@string/open_in_browser"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/dragHandle"
|
||||
app:layout_constraintTop_toBottomOf="@id/headerBar"
|
||||
app:tint="?android:colorControlNormal" />
|
||||
|
||||
<RatingBar
|
||||
|
||||
@@ -93,6 +93,10 @@
|
||||
<attr name="fitStatusBar" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="AdaptiveSheetHeaderBar">
|
||||
<attr name="title" />
|
||||
</declare-styleable>
|
||||
|
||||
<declare-styleable name="ShapeView">
|
||||
<attr name="strokeWidth" />
|
||||
<attr name="strokeColor" />
|
||||
|
||||
@@ -68,4 +68,5 @@
|
||||
<dimen name="fastscroll_scrollbar_padding_start">6dp</dimen>
|
||||
<dimen name="fastscroll_scrollbar_padding_end">6dp</dimen>
|
||||
|
||||
<dimen name="m3_side_sheet_width">400dp</dimen>
|
||||
</resources>
|
||||
|
||||
Reference in New Issue
Block a user