Enhance manga search suggestion
parent
abc2fb0e40
commit
25d52c5a61
@ -1,46 +0,0 @@
|
|||||||
package org.koitharu.kotatsu.search.ui.suggestion.adapter
|
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
|
||||||
import coil.ImageLoader
|
|
||||||
import coil.request.Disposable
|
|
||||||
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
|
||||||
import org.koitharu.kotatsu.R
|
|
||||||
import org.koitharu.kotatsu.databinding.ItemSearchSuggestionMangaBinding
|
|
||||||
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
|
|
||||||
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
|
|
||||||
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
|
||||||
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
|
||||||
import org.koitharu.kotatsu.utils.ext.textAndVisible
|
|
||||||
|
|
||||||
fun searchSuggestionMangaAD(
|
|
||||||
coil: ImageLoader,
|
|
||||||
lifecycleOwner: LifecycleOwner,
|
|
||||||
listener: SearchSuggestionListener,
|
|
||||||
) = adapterDelegateViewBinding<SearchSuggestionItem.MangaItem, SearchSuggestionItem, ItemSearchSuggestionMangaBinding>(
|
|
||||||
{ inflater, parent -> ItemSearchSuggestionMangaBinding.inflate(inflater, parent, false) }
|
|
||||||
) {
|
|
||||||
|
|
||||||
var imageRequest: Disposable? = null
|
|
||||||
|
|
||||||
itemView.setOnClickListener {
|
|
||||||
listener.onMangaClick(item.manga)
|
|
||||||
}
|
|
||||||
|
|
||||||
bind {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
imageRequest = binding.imageViewCover.newImageRequest(item.manga.coverUrl)
|
|
||||||
.placeholder(R.drawable.ic_placeholder)
|
|
||||||
.fallback(R.drawable.ic_placeholder)
|
|
||||||
.error(R.drawable.ic_placeholder)
|
|
||||||
.allowRgb565(true)
|
|
||||||
.lifecycle(lifecycleOwner)
|
|
||||||
.enqueueWith(coil)
|
|
||||||
binding.textViewTitle.text = item.manga.title
|
|
||||||
binding.textViewSubtitle.textAndVisible = item.manga.altTitle
|
|
||||||
}
|
|
||||||
|
|
||||||
onViewRecycled {
|
|
||||||
imageRequest?.dispose()
|
|
||||||
binding.imageViewCover.setImageDrawable(null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
package org.koitharu.kotatsu.search.ui.suggestion.adapter
|
||||||
|
|
||||||
|
import androidx.core.view.updatePadding
|
||||||
|
import androidx.lifecycle.LifecycleOwner
|
||||||
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import coil.ImageLoader
|
||||||
|
import coil.request.Disposable
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.AsyncListDifferDelegationAdapter
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegate
|
||||||
|
import com.hannesdorfmann.adapterdelegates4.dsl.adapterDelegateViewBinding
|
||||||
|
import org.koitharu.kotatsu.R
|
||||||
|
import org.koitharu.kotatsu.base.ui.list.decor.SpacingItemDecoration
|
||||||
|
import org.koitharu.kotatsu.core.model.Manga
|
||||||
|
import org.koitharu.kotatsu.databinding.ItemSearchSuggestionMangaGridBinding
|
||||||
|
import org.koitharu.kotatsu.search.ui.suggestion.SearchSuggestionListener
|
||||||
|
import org.koitharu.kotatsu.search.ui.suggestion.model.SearchSuggestionItem
|
||||||
|
import org.koitharu.kotatsu.utils.ScrollResetCallback
|
||||||
|
import org.koitharu.kotatsu.utils.ext.enqueueWith
|
||||||
|
import org.koitharu.kotatsu.utils.ext.newImageRequest
|
||||||
|
|
||||||
|
fun searchSuggestionMangaListAD(
|
||||||
|
coil: ImageLoader,
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
listener: SearchSuggestionListener,
|
||||||
|
) = adapterDelegate<SearchSuggestionItem.MangaList, SearchSuggestionItem>(R.layout.item_search_suggestion_manga_list) {
|
||||||
|
|
||||||
|
val adapter = AsyncListDifferDelegationAdapter(
|
||||||
|
SuggestionMangaDiffCallback(),
|
||||||
|
searchSuggestionMangaGridAD(coil, lifecycleOwner, listener),
|
||||||
|
)
|
||||||
|
val recyclerView = itemView as RecyclerView
|
||||||
|
recyclerView.adapter = adapter
|
||||||
|
val spacing = context.resources.getDimensionPixelOffset(R.dimen.search_suggestions_manga_spacing)
|
||||||
|
recyclerView.updatePadding(
|
||||||
|
left = recyclerView.paddingLeft - spacing,
|
||||||
|
right = recyclerView.paddingRight - spacing,
|
||||||
|
)
|
||||||
|
recyclerView.addItemDecoration(SpacingItemDecoration(spacing))
|
||||||
|
val scrollResetCallback = ScrollResetCallback(recyclerView)
|
||||||
|
|
||||||
|
bind {
|
||||||
|
adapter.setItems(item.items, scrollResetCallback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun searchSuggestionMangaGridAD(
|
||||||
|
coil: ImageLoader,
|
||||||
|
lifecycleOwner: LifecycleOwner,
|
||||||
|
listener: SearchSuggestionListener,
|
||||||
|
) = adapterDelegateViewBinding<Manga, Manga, ItemSearchSuggestionMangaGridBinding>(
|
||||||
|
{ layoutInflater, parent -> ItemSearchSuggestionMangaGridBinding.inflate(layoutInflater, parent, false) }
|
||||||
|
) {
|
||||||
|
|
||||||
|
var imageRequest: Disposable? = null
|
||||||
|
|
||||||
|
itemView.setOnClickListener {
|
||||||
|
listener.onMangaClick(item)
|
||||||
|
}
|
||||||
|
|
||||||
|
bind {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
imageRequest = binding.imageViewCover.newImageRequest(item.coverUrl)
|
||||||
|
.placeholder(R.drawable.ic_placeholder)
|
||||||
|
.fallback(R.drawable.ic_placeholder)
|
||||||
|
.error(R.drawable.ic_placeholder)
|
||||||
|
.allowRgb565(true)
|
||||||
|
.lifecycle(lifecycleOwner)
|
||||||
|
.enqueueWith(coil)
|
||||||
|
binding.textViewTitle.text = item.title
|
||||||
|
}
|
||||||
|
|
||||||
|
onViewRecycled {
|
||||||
|
imageRequest?.dispose()
|
||||||
|
binding.imageViewCover.setImageDrawable(null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class SuggestionMangaDiffCallback : DiffUtil.ItemCallback<Manga>() {
|
||||||
|
|
||||||
|
override fun areItemsTheSame(oldItem: Manga, newItem: Manga): Boolean {
|
||||||
|
return oldItem.id == newItem.id
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun areContentsTheSame(oldItem: Manga, newItem: Manga): Boolean {
|
||||||
|
return oldItem.title == newItem.title && oldItem.coverUrl == newItem.coverUrl
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
package org.koitharu.kotatsu.utils
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
class ScrollResetCallback(recyclerView: RecyclerView) : Runnable {
|
||||||
|
|
||||||
|
private val recyclerViewRef = WeakReference(recyclerView)
|
||||||
|
|
||||||
|
override fun run() {
|
||||||
|
recyclerViewRef.get()?.scrollToPosition(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,46 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:background="?selectableItemBackground"
|
|
||||||
android:gravity="center_vertical"
|
|
||||||
android:paddingStart="?listPreferredItemPaddingStart"
|
|
||||||
android:paddingTop="2dp"
|
|
||||||
android:paddingEnd="?listPreferredItemPaddingEnd"
|
|
||||||
android:paddingBottom="2dp">
|
|
||||||
|
|
||||||
<org.koitharu.kotatsu.base.ui.widgets.CoverImageView
|
|
||||||
android:id="@+id/imageView_cover"
|
|
||||||
android:layout_width="42dp"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="12dp"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView_title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodyMedium"
|
|
||||||
tools:text="@tools:sample/lorem[6]" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/textView_subtitle"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:ellipsize="end"
|
|
||||||
android:singleLine="true"
|
|
||||||
android:textAppearance="?attr/textAppearanceBodySmall"
|
|
||||||
android:textColor="?android:textColorSecondary"
|
|
||||||
tools:text="@tools:sample/lorem[6]" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<com.google.android.material.card.MaterialCardView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
style="@style/Widget.Material3.CardView.Outlined"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:contentPadding="4dp"
|
||||||
|
tools:layout_height="@dimen/search_suggestions_manga_height">
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<org.koitharu.kotatsu.base.ui.widgets.CoverImageView
|
||||||
|
android:id="@+id/imageView_cover"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_weight="1"
|
||||||
|
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Kotatsu.Cover.Small"
|
||||||
|
android:orientation="vertical"
|
||||||
|
android:scaleType="centerCrop"
|
||||||
|
tools:src="@tools:sample/backgrounds/scenic" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/textView_title"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:elegantTextHeight="false"
|
||||||
|
android:ellipsize="end"
|
||||||
|
android:lines="1"
|
||||||
|
android:textAppearance="?attr/textAppearanceLabelSmall"
|
||||||
|
tools:text="@tools:sample/lorem[6]" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
</com.google.android.material.card.MaterialCardView>
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:orientation="horizontal"
|
||||||
|
android:scrollbars="none"
|
||||||
|
android:clipChildren="false"
|
||||||
|
android:clipToPadding="false"
|
||||||
|
android:paddingStart="?listPreferredItemPaddingStart"
|
||||||
|
android:paddingEnd="?listPreferredItemPaddingEnd"
|
||||||
|
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||||
|
tools:listitem="@layout/item_search_suggestion_manga_grid"
|
||||||
|
android:layout_height="@dimen/search_suggestions_manga_height" />
|
||||||
Loading…
Reference in New Issue