From 8b95d93a96e6a5c520ae5fc5e631b612cedd0b90 Mon Sep 17 00:00:00 2001 From: Jobobby04 Date: Thu, 16 Jul 2020 17:27:36 -0400 Subject: [PATCH] Add custom tag view for namespaced sources (E-Hentai, nHentai, Hitomi.la, and Pururin) --- .../ui/manga/info/MangaInfoHeaderAdapter.kt | 36 +++++++++++++- .../ui/manga/info/NamespaceTagsItem.kt | 47 +++++++++++++++++++ app/src/main/java/exh/util/SourceTagsUtil.kt | 2 + app/src/main/java/exh/util/ViewExtensions.kt | 24 ++++++---- .../res/layout/manga_info_genre_grouping.xml | 23 +++++++++ app/src/main/res/layout/manga_info_header.xml | 9 ++++ 6 files changed, 129 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/NamespaceTagsItem.kt create mode 100644 app/src/main/res/layout/manga_info_genre_grouping.xml diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt index d1294c0f1..7cac57584 100644 --- a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/MangaInfoHeaderAdapter.kt @@ -7,8 +7,11 @@ import android.view.View import android.view.ViewGroup import androidx.core.content.ContextCompat import androidx.core.view.isVisible +import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.RecyclerView 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.data.database.models.Manga 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.visible 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.NHENTAI_SOURCE_ID +import exh.PURURIN_SOURCE_ID import exh.util.SourceTagsUtil +import exh.util.makeSearchChip import exh.util.setChipsExtended import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers @@ -66,6 +75,8 @@ class MangaInfoHeaderAdapter( holder.bind() } + val tagsAdapter: FlexibleAdapter> = FlexibleAdapter(null) + /** * Update the view with manga information. * @@ -229,6 +240,11 @@ class MangaInfoHeaderAdapter( } // EXH <-- + // SY --> + binding.mangaNamespaceTagsRecycler.layoutManager = LinearLayoutManager(itemView.context) + binding.mangaNamespaceTagsRecycler.adapter = tagsAdapter + // SY <-- + setMangaInfo(manga, source) } @@ -320,8 +336,18 @@ class MangaInfoHeaderAdapter( // Update genres list if (!manga.genre.isNullOrBlank()) { // 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.mangaGenresTagsCompactChips.setChipsExtended(manga.getGenres(), controller::performSearch, controller::performGlobalSearch, source?.id ?: 0) // SY <-- } else { binding.mangaGenresTagsWrapper.gone() @@ -387,7 +413,13 @@ class MangaInfoHeaderAdapter( } 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 <-- } /** diff --git a/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/NamespaceTagsItem.kt b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/NamespaceTagsItem.kt new file mode 100644 index 000000000..731f27422 --- /dev/null +++ b/app/src/main/java/eu/kanade/tachiyomi/ui/manga/info/NamespaceTagsItem.kt @@ -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) : AbstractFlexibleItem() { + + override fun getLayoutRes(): Int { + return R.layout.manga_info_genre_grouping + } + + override fun createViewHolder(view: View, adapter: FlexibleAdapter>): Holder { + return Holder(view, adapter) + } + + override fun bindViewHolder(adapter: FlexibleAdapter>, holder: Holder, position: Int, payloads: List?) { + 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) + } +} diff --git a/app/src/main/java/exh/util/SourceTagsUtil.kt b/app/src/main/java/exh/util/SourceTagsUtil.kt index cf87cdffe..1716885ba 100644 --- a/app/src/main/java/exh/util/SourceTagsUtil.kt +++ b/app/src/main/java/exh/util/SourceTagsUtil.kt @@ -4,6 +4,7 @@ import exh.EH_SOURCE_ID import exh.EXH_SOURCE_ID import exh.HITOMI_SOURCE_ID import exh.NHENTAI_SOURCE_ID +import exh.PURURIN_SOURCE_ID class SourceTagsUtil { fun getWrappedTag(sourceId: Long, namespace: String? = null, tag: String? = null, fullTag: String? = null): String? { @@ -13,6 +14,7 @@ class SourceTagsUtil { when (sourceId) { HITOMI_SOURCE_ID -> wrapTagHitomi(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 null diff --git a/app/src/main/java/exh/util/ViewExtensions.kt b/app/src/main/java/exh/util/ViewExtensions.kt index 019940dfb..4fbf93a63 100644 --- a/app/src/main/java/exh/util/ViewExtensions.kt +++ b/app/src/main/java/exh/util/ViewExtensions.kt @@ -1,5 +1,6 @@ package exh.util +import android.content.Context import android.view.View import android.view.ViewGroup import android.view.WindowInsets @@ -114,16 +115,19 @@ fun ChipGroup.setChipsExtended(items: List?, onClick: (item: String) -> removeAllViews() items?.forEach { item -> - val chip = Chip(context).apply { - text = item - val search = SourceTagsUtil().getWrappedTag(sourceId, fullTag = item) ?: item - setOnClickListener { onClick(search) } - setOnLongClickListener { - onLongClick(search) - false - } - } - + val chip = makeSearchChip(item, onClick, onLongClick, sourceId, context) 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 + } + } +} diff --git a/app/src/main/res/layout/manga_info_genre_grouping.xml b/app/src/main/res/layout/manga_info_genre_grouping.xml new file mode 100644 index 000000000..7b802c173 --- /dev/null +++ b/app/src/main/res/layout/manga_info_genre_grouping.xml @@ -0,0 +1,23 @@ + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/manga_info_header.xml b/app/src/main/res/layout/manga_info_header.xml index d708e5ff8..0c6899cf5 100644 --- a/app/src/main/res/layout/manga_info_header.xml +++ b/app/src/main/res/layout/manga_info_header.xml @@ -244,6 +244,15 @@ android:textIsSelectable="false" tools:text="Summary" /> + +