Implement new manga sources settings list screen #78
parent
a2dbec98f9
commit
229a7c70d9
@ -0,0 +1,65 @@
|
|||||||
|
package org.koitharu.kotatsu.base.ui.list.decor
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Rect
|
||||||
|
import android.view.View
|
||||||
|
import androidx.core.view.children
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.koitharu.kotatsu.utils.ext.getThemeDrawable
|
||||||
|
import kotlin.math.roundToInt
|
||||||
|
|
||||||
|
abstract class AbstractDividerItemDecoration(context: Context) : RecyclerView.ItemDecoration() {
|
||||||
|
|
||||||
|
private val bounds = Rect()
|
||||||
|
private val divider = context.getThemeDrawable(android.R.attr.listDivider)
|
||||||
|
|
||||||
|
override fun getItemOffsets(
|
||||||
|
outRect: Rect,
|
||||||
|
view: View,
|
||||||
|
parent: RecyclerView,
|
||||||
|
state: RecyclerView.State,
|
||||||
|
) {
|
||||||
|
outRect.set(0, divider?.intrinsicHeight ?: 0, 0, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO implement for horizontal lists on demand
|
||||||
|
override fun onDraw(canvas: Canvas, parent: RecyclerView, s: RecyclerView.State) {
|
||||||
|
if (parent.layoutManager == null || divider == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
canvas.save()
|
||||||
|
val left: Int
|
||||||
|
val right: Int
|
||||||
|
if (parent.clipToPadding) {
|
||||||
|
left = parent.paddingLeft
|
||||||
|
right = parent.width - parent.paddingRight
|
||||||
|
canvas.clipRect(
|
||||||
|
left, parent.paddingTop, right,
|
||||||
|
parent.height - parent.paddingBottom
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
left = 0
|
||||||
|
right = parent.width
|
||||||
|
}
|
||||||
|
|
||||||
|
var previous: RecyclerView.ViewHolder? = null
|
||||||
|
for (child in parent.children) {
|
||||||
|
val holder = parent.getChildViewHolder(child)
|
||||||
|
if (previous != null && shouldDrawDivider(previous, holder)) {
|
||||||
|
parent.getDecoratedBoundsWithMargins(child, bounds)
|
||||||
|
val top: Int = bounds.top + child.translationY.roundToInt()
|
||||||
|
val bottom: Int = top + divider.intrinsicHeight
|
||||||
|
divider.setBounds(left, top, right, bottom)
|
||||||
|
divider.draw(canvas)
|
||||||
|
}
|
||||||
|
previous = holder
|
||||||
|
}
|
||||||
|
canvas.restore()
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract fun shouldDrawDivider(
|
||||||
|
above: RecyclerView.ViewHolder,
|
||||||
|
below: RecyclerView.ViewHolder,
|
||||||
|
): Boolean
|
||||||
|
}
|
||||||
@ -1,11 +1,13 @@
|
|||||||
package org.koitharu.kotatsu.settings.sources.adapter
|
package org.koitharu.kotatsu.settings.sources.adapter
|
||||||
|
|
||||||
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
|
|
||||||
class SourceConfigAdapter(
|
class SourceConfigAdapter(
|
||||||
listener: SourceConfigListener,
|
listener: SourceConfigListener,
|
||||||
) : AsyncListDifferDelegationAdapter<SourceConfigItem>(
|
) : AsyncListDifferDelegationAdapter<SourceConfigItem>(
|
||||||
SourceConfigDiffCallback(),
|
SourceConfigDiffCallback(),
|
||||||
sourceConfigHeaderDelegate(listener),
|
sourceConfigHeaderDelegate(),
|
||||||
|
sourceConfigGroupDelegate(listener),
|
||||||
sourceConfigItemDelegate(listener),
|
sourceConfigItemDelegate(listener),
|
||||||
)
|
)
|
||||||
@ -1,32 +1,28 @@
|
|||||||
package org.koitharu.kotatsu.settings.sources.adapter
|
package org.koitharu.kotatsu.settings.sources.adapter
|
||||||
|
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import org.koitharu.kotatsu.settings.sources.model.SourceConfigItem
|
||||||
|
|
||||||
class SourceConfigDiffCallback : DiffUtil.ItemCallback<SourceConfigItem>() {
|
class SourceConfigDiffCallback : DiffUtil.ItemCallback<SourceConfigItem>() {
|
||||||
|
|
||||||
override fun areItemsTheSame(oldItem: SourceConfigItem, newItem: SourceConfigItem): Boolean {
|
override fun areItemsTheSame(oldItem: SourceConfigItem, newItem: SourceConfigItem): Boolean {
|
||||||
return when {
|
return when {
|
||||||
oldItem.javaClass != newItem.javaClass -> false
|
oldItem.javaClass != newItem.javaClass -> false
|
||||||
oldItem is SourceConfigItem.LocaleHeader && newItem is SourceConfigItem.LocaleHeader -> {
|
oldItem is SourceConfigItem.LocaleGroup && newItem is SourceConfigItem.LocaleGroup -> {
|
||||||
oldItem.localeId == newItem.localeId
|
oldItem.localeId == newItem.localeId
|
||||||
}
|
}
|
||||||
oldItem is SourceConfigItem.SourceItem && newItem is SourceConfigItem.SourceItem -> {
|
oldItem is SourceConfigItem.SourceItem && newItem is SourceConfigItem.SourceItem -> {
|
||||||
oldItem.source == newItem.source
|
oldItem.source == newItem.source
|
||||||
}
|
}
|
||||||
|
oldItem is SourceConfigItem.Header && newItem is SourceConfigItem.Header -> {
|
||||||
|
oldItem.titleResId == newItem.titleResId
|
||||||
|
}
|
||||||
else -> false
|
else -> false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: SourceConfigItem, newItem: SourceConfigItem): Boolean {
|
override fun areContentsTheSame(oldItem: SourceConfigItem, newItem: SourceConfigItem): Boolean {
|
||||||
return when {
|
return oldItem == newItem
|
||||||
oldItem is SourceConfigItem.LocaleHeader && newItem is SourceConfigItem.LocaleHeader -> {
|
|
||||||
oldItem.title == newItem.title && oldItem.isExpanded == newItem.isExpanded
|
|
||||||
}
|
|
||||||
oldItem is SourceConfigItem.SourceItem && newItem is SourceConfigItem.SourceItem -> {
|
|
||||||
oldItem.isEnabled == newItem.isEnabled
|
|
||||||
}
|
|
||||||
else -> false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getChangePayload(oldItem: SourceConfigItem, newItem: SourceConfigItem) = Unit
|
override fun getChangePayload(oldItem: SourceConfigItem, newItem: SourceConfigItem) = Unit
|
||||||
|
|||||||
@ -1,17 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.settings.sources.adapter
|
|
||||||
|
|
||||||
import org.koitharu.kotatsu.core.model.MangaSource
|
|
||||||
|
|
||||||
sealed interface SourceConfigItem {
|
|
||||||
|
|
||||||
data class LocaleHeader(
|
|
||||||
val localeId: String?,
|
|
||||||
val title: String?,
|
|
||||||
val isExpanded: Boolean,
|
|
||||||
) : SourceConfigItem
|
|
||||||
|
|
||||||
data class SourceItem(
|
|
||||||
val source: MangaSource,
|
|
||||||
val isEnabled: Boolean,
|
|
||||||
) : SourceConfigItem
|
|
||||||
}
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.sources.adapter
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.decor.AbstractDividerItemDecoration
|
||||||
|
|
||||||
|
class SourceConfigItemDecoration(context: Context) : AbstractDividerItemDecoration(context) {
|
||||||
|
|
||||||
|
override fun shouldDrawDivider(
|
||||||
|
above: RecyclerView.ViewHolder,
|
||||||
|
below: RecyclerView.ViewHolder,
|
||||||
|
): Boolean {
|
||||||
|
return above.itemViewType != 0 && below.itemViewType != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,72 @@
|
|||||||
|
package org.koitharu.kotatsu.settings.sources.model
|
||||||
|
|
||||||
|
import androidx.annotation.StringRes
|
||||||
|
import org.koitharu.kotatsu.core.model.MangaSource
|
||||||
|
|
||||||
|
sealed interface SourceConfigItem {
|
||||||
|
|
||||||
|
class Header(
|
||||||
|
@StringRes val titleResId: Int,
|
||||||
|
) : SourceConfigItem {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
other as Header
|
||||||
|
return titleResId == other.titleResId
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int = titleResId
|
||||||
|
}
|
||||||
|
|
||||||
|
class LocaleGroup(
|
||||||
|
val localeId: String?,
|
||||||
|
val title: String?,
|
||||||
|
val isExpanded: Boolean,
|
||||||
|
) : SourceConfigItem {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as LocaleGroup
|
||||||
|
|
||||||
|
if (localeId != other.localeId) return false
|
||||||
|
if (title != other.title) return false
|
||||||
|
if (isExpanded != other.isExpanded) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = localeId?.hashCode() ?: 0
|
||||||
|
result = 31 * result + (title?.hashCode() ?: 0)
|
||||||
|
result = 31 * result + isExpanded.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SourceItem(
|
||||||
|
val source: MangaSource,
|
||||||
|
val isEnabled: Boolean,
|
||||||
|
) : SourceConfigItem {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
|
||||||
|
other as SourceItem
|
||||||
|
|
||||||
|
if (source != other.source) return false
|
||||||
|
if (isEnabled != other.isEnabled) return false
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = source.hashCode()
|
||||||
|
result = 31 * result + isEnabled.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue