Add custom tag view for namespaced sources (E-Hentai, nHentai, Hitomi.la, and Pururin)
This commit is contained in:
parent
74012e0830
commit
8b95d93a96
@ -7,8 +7,11 @@ import android.view.View
|
|||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
import androidx.core.view.isVisible
|
import androidx.core.view.isVisible
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
import eu.kanade.tachiyomi.R
|
import eu.kanade.tachiyomi.R
|
||||||
import eu.kanade.tachiyomi.data.database.models.Manga
|
import eu.kanade.tachiyomi.data.database.models.Manga
|
||||||
import eu.kanade.tachiyomi.data.glide.GlideApp
|
import eu.kanade.tachiyomi.data.glide.GlideApp
|
||||||
@ -27,8 +30,14 @@ import eu.kanade.tachiyomi.util.view.gone
|
|||||||
import eu.kanade.tachiyomi.util.view.setTooltip
|
import eu.kanade.tachiyomi.util.view.setTooltip
|
||||||
import eu.kanade.tachiyomi.util.view.visible
|
import eu.kanade.tachiyomi.util.view.visible
|
||||||
import eu.kanade.tachiyomi.util.view.visibleIf
|
import eu.kanade.tachiyomi.util.view.visibleIf
|
||||||
|
import exh.EH_SOURCE_ID
|
||||||
|
import exh.EXH_SOURCE_ID
|
||||||
|
import exh.HITOMI_SOURCE_ID
|
||||||
import exh.MERGED_SOURCE_ID
|
import exh.MERGED_SOURCE_ID
|
||||||
|
import exh.NHENTAI_SOURCE_ID
|
||||||
|
import exh.PURURIN_SOURCE_ID
|
||||||
import exh.util.SourceTagsUtil
|
import exh.util.SourceTagsUtil
|
||||||
|
import exh.util.makeSearchChip
|
||||||
import exh.util.setChipsExtended
|
import exh.util.setChipsExtended
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
@ -66,6 +75,8 @@ class MangaInfoHeaderAdapter(
|
|||||||
holder.bind()
|
holder.bind()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val tagsAdapter: FlexibleAdapter<IFlexible<*>> = FlexibleAdapter(null)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the view with manga information.
|
* Update the view with manga information.
|
||||||
*
|
*
|
||||||
@ -229,6 +240,11 @@ class MangaInfoHeaderAdapter(
|
|||||||
}
|
}
|
||||||
// EXH <--
|
// EXH <--
|
||||||
|
|
||||||
|
// SY -->
|
||||||
|
binding.mangaNamespaceTagsRecycler.layoutManager = LinearLayoutManager(itemView.context)
|
||||||
|
binding.mangaNamespaceTagsRecycler.adapter = tagsAdapter
|
||||||
|
// SY <--
|
||||||
|
|
||||||
setMangaInfo(manga, source)
|
setMangaInfo(manga, source)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,8 +336,18 @@ class MangaInfoHeaderAdapter(
|
|||||||
// Update genres list
|
// Update genres list
|
||||||
if (!manga.genre.isNullOrBlank()) {
|
if (!manga.genre.isNullOrBlank()) {
|
||||||
// SY -->
|
// SY -->
|
||||||
binding.mangaGenresTagsCompactChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
if (source != null && (source.id == EH_SOURCE_ID || source.id == EXH_SOURCE_ID || source.id == NHENTAI_SOURCE_ID || source.id == HITOMI_SOURCE_ID || source.id == PURURIN_SOURCE_ID)) {
|
||||||
|
val genre = manga.getGenres()
|
||||||
|
if (!genre.isNullOrEmpty()) {
|
||||||
|
val namespaceTags = genre.map { SourceTagsUtil().parseTag(it) }
|
||||||
|
.groupBy { it.first }
|
||||||
|
.mapValues { values -> values.value.map { makeSearchChip(it.second, controller::performSearch, controller::performGlobalSearch, source.id, itemView.context, it.first) } }
|
||||||
|
.map { NamespaceTagsItem(it.key, it.value) }
|
||||||
|
tagsAdapter.updateDataSet(namespaceTags)
|
||||||
|
}
|
||||||
|
}
|
||||||
binding.mangaGenresTagsFullChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
binding.mangaGenresTagsFullChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
||||||
|
binding.mangaGenresTagsCompactChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0)
|
||||||
// SY <--
|
// SY <--
|
||||||
} else {
|
} else {
|
||||||
binding.mangaGenresTagsWrapper.gone()
|
binding.mangaGenresTagsWrapper.gone()
|
||||||
@ -387,7 +413,13 @@ class MangaInfoHeaderAdapter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
binding.mangaGenresTagsCompact.visibleIf { isExpanded }
|
||||||
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
// SY -->
|
||||||
|
if (source.id == EH_SOURCE_ID || source.id == EXH_SOURCE_ID || source.id == NHENTAI_SOURCE_ID || source.id == HITOMI_SOURCE_ID || source.id == PURURIN_SOURCE_ID) {
|
||||||
|
binding.mangaNamespaceTagsRecycler.visibleIf { !isExpanded }
|
||||||
|
} else {
|
||||||
|
binding.mangaGenresTagsFullChips.visibleIf { !isExpanded }
|
||||||
|
}
|
||||||
|
// SY <--
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -0,0 +1,47 @@
|
|||||||
|
package eu.kanade.tachiyomi.ui.manga.info
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.chip.Chip
|
||||||
|
import com.google.android.material.chip.ChipGroup
|
||||||
|
import eu.davidea.flexibleadapter.FlexibleAdapter
|
||||||
|
import eu.davidea.flexibleadapter.items.AbstractFlexibleItem
|
||||||
|
import eu.davidea.flexibleadapter.items.IFlexible
|
||||||
|
import eu.davidea.viewholders.FlexibleViewHolder
|
||||||
|
import eu.kanade.tachiyomi.R
|
||||||
|
|
||||||
|
open class NamespaceTagsItem(val namespace: String, val tags: List<Chip>) : AbstractFlexibleItem<NamespaceTagsItem.Holder>() {
|
||||||
|
|
||||||
|
override fun getLayoutRes(): Int {
|
||||||
|
return R.layout.manga_info_genre_grouping
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createViewHolder(view: View, adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>): Holder {
|
||||||
|
return Holder(view, adapter)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun bindViewHolder(adapter: FlexibleAdapter<IFlexible<RecyclerView.ViewHolder>>, holder: Holder, position: Int, payloads: List<Any?>?) {
|
||||||
|
val namespaceChip = Chip(holder.itemView.context)
|
||||||
|
namespaceChip.text = namespace
|
||||||
|
holder.namespaceChipGroup.addView(namespaceChip)
|
||||||
|
|
||||||
|
tags.forEach {
|
||||||
|
holder.tagsChipGroup.addView(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (this === other) return true
|
||||||
|
if (javaClass != other?.javaClass) return false
|
||||||
|
return namespace == (other as NamespaceTagsItem).namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
return namespace.hashCode()
|
||||||
|
}
|
||||||
|
|
||||||
|
class Holder(view: View, adapter: FlexibleAdapter<*>) : FlexibleViewHolder(view, adapter) {
|
||||||
|
val namespaceChipGroup: ChipGroup = itemView.findViewById(R.id.namespace)
|
||||||
|
val tagsChipGroup: ChipGroup = itemView.findViewById(R.id.tags)
|
||||||
|
}
|
||||||
|
}
|
@ -4,6 +4,7 @@ import exh.EH_SOURCE_ID
|
|||||||
import exh.EXH_SOURCE_ID
|
import exh.EXH_SOURCE_ID
|
||||||
import exh.HITOMI_SOURCE_ID
|
import exh.HITOMI_SOURCE_ID
|
||||||
import exh.NHENTAI_SOURCE_ID
|
import exh.NHENTAI_SOURCE_ID
|
||||||
|
import exh.PURURIN_SOURCE_ID
|
||||||
|
|
||||||
class SourceTagsUtil {
|
class SourceTagsUtil {
|
||||||
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
|
fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? {
|
||||||
@ -13,6 +14,7 @@ class SourceTagsUtil {
|
|||||||
when (sourceId) {
|
when (sourceId) {
|
||||||
HITOMI_SOURCE_ID -> wrapTagHitomi(parsed.first, parsed.second.substringBefore('|').trim())
|
HITOMI_SOURCE_ID -> wrapTagHitomi(parsed.first, parsed.second.substringBefore('|').trim())
|
||||||
NHENTAI_SOURCE_ID -> wrapTagNHentai(parsed.first, parsed.second.substringBefore('|').trim())
|
NHENTAI_SOURCE_ID -> wrapTagNHentai(parsed.first, parsed.second.substringBefore('|').trim())
|
||||||
|
PURURIN_SOURCE_ID -> parsed.second.substringBefore('|').trim()
|
||||||
else -> wrapTag(parsed.first, parsed.second.substringBefore('|').trim())
|
else -> wrapTag(parsed.first, parsed.second.substringBefore('|').trim())
|
||||||
}
|
}
|
||||||
} else null
|
} else null
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package exh.util
|
package exh.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.view.WindowInsets
|
import android.view.WindowInsets
|
||||||
@ -114,16 +115,19 @@ fun ChipGroup.setChipsExtended(items: List<String>?, onClick: (item: String) ->
|
|||||||
removeAllViews()
|
removeAllViews()
|
||||||
|
|
||||||
items?.forEach { item ->
|
items?.forEach { item ->
|
||||||
val chip = Chip(context).apply {
|
val chip = makeSearchChip(item, onClick, onLongClick, sourceId, context)
|
||||||
text = item
|
|
||||||
val search = SourceTagsUtil().getWrappedTag(sourceId, fullTag = item) ?: item
|
|
||||||
setOnClickListener { onClick(search) }
|
|
||||||
setOnLongClickListener {
|
|
||||||
onLongClick(search)
|
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
addView(chip)
|
addView(chip)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun makeSearchChip(item: String, onClick: (item: String) -> Unit = {}, onLongClick: (item: String) -> Unit = {}, sourceId: Long, context: Context, namespace: String? = null): Chip {
|
||||||
|
return Chip(context).apply {
|
||||||
|
text = item
|
||||||
|
val search = (if (namespace != null) SourceTagsUtil().getWrappedTag(sourceId, namespace = namespace, tag = item) else SourceTagsUtil().getWrappedTag(sourceId, fullTag = item)) ?: item
|
||||||
|
setOnClickListener { onClick(search) }
|
||||||
|
setOnLongClickListener {
|
||||||
|
onLongClick(search)
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
23
app/src/main/res/layout/manga_info_genre_grouping.xml
Normal file
23
app/src/main/res/layout/manga_info_genre_grouping.xml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
<?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:orientation="horizontal"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/namespace"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
app:chipSpacingHorizontal="4dp"/>
|
||||||
|
|
||||||
|
<com.google.android.material.chip.ChipGroup
|
||||||
|
android:id="@+id/tags"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
app:chipSpacingHorizontal="4dp"/>
|
||||||
|
|
||||||
|
</LinearLayout>
|
@ -244,6 +244,15 @@
|
|||||||
android:textIsSelectable="false"
|
android:textIsSelectable="false"
|
||||||
tools:text="Summary" />
|
tools:text="Summary" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/manga_namespace_tags_recycler"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginBottom="8dp"
|
||||||
|
android:visibility="gone"
|
||||||
|
tools:listitem="@layout/manga_info_genre_grouping"/>
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/manga_genres_tags_wrapper"
|
android:id="@+id/manga_genres_tags_wrapper"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user