Add item count to media items
This commit is contained in:
parent
6c220619ef
commit
930cf764ca
9 changed files with 62 additions and 41 deletions
|
@ -28,16 +28,20 @@ fun bindViews(recyclerView: RecyclerView, data: List<View>?) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@BindingAdapter("items")
|
@BindingAdapter("items")
|
||||||
fun bindItems(recyclerView: RecyclerView, data: List<ViewItem>?) {
|
fun bindItems(recyclerView: RecyclerView, data: List<BaseItemDto>?) {
|
||||||
val adapter = recyclerView.adapter as ViewItemListAdapter
|
val adapter = recyclerView.adapter as ViewItemListAdapter
|
||||||
adapter.submitList(data)
|
adapter.submitList(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
@BindingAdapter("itemImage")
|
@BindingAdapter("itemImage")
|
||||||
fun bindItemImage(imageView: ImageView, item: ViewItem) {
|
fun bindItemImage(imageView: ImageView, item: BaseItemDto) {
|
||||||
|
val jellyfinApi = JellyfinApi.getInstance(imageView.context.applicationContext, "")
|
||||||
|
|
||||||
|
val itemId = if (item.type == "Episode") item.seriesId else item.id
|
||||||
|
|
||||||
Glide
|
Glide
|
||||||
.with(imageView.context)
|
.with(imageView.context)
|
||||||
.load(item.primaryImageUrl)
|
.load(jellyfinApi.api.baseUrl.plus("/items/${itemId}/Images/Primary"))
|
||||||
.transition(DrawableTransitionOptions.withCrossFade())
|
.transition(DrawableTransitionOptions.withCrossFade())
|
||||||
.placeholder(R.color.neutral_800)
|
.placeholder(R.color.neutral_800)
|
||||||
.into(imageView)
|
.into(imageView)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package dev.jdtech.jellyfin.adapters
|
package dev.jdtech.jellyfin.adapters
|
||||||
|
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.recyclerview.widget.DiffUtil
|
import androidx.recyclerview.widget.DiffUtil
|
||||||
import androidx.recyclerview.widget.ListAdapter
|
import androidx.recyclerview.widget.ListAdapter
|
||||||
|
@ -9,26 +10,37 @@ import dev.jdtech.jellyfin.databinding.BaseItemBinding
|
||||||
import dev.jdtech.jellyfin.models.ViewItem
|
import dev.jdtech.jellyfin.models.ViewItem
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
|
|
||||||
class ViewItemListAdapter : ListAdapter<ViewItem, ViewItemListAdapter.ItemViewHolder>(DiffCallback) {
|
class ViewItemListAdapter :
|
||||||
class ItemViewHolder(private var binding: BaseItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
ListAdapter<BaseItemDto, ViewItemListAdapter.ItemViewHolder>(DiffCallback) {
|
||||||
fun bind(view: ViewItem) {
|
class ItemViewHolder(private var binding: BaseItemBinding) :
|
||||||
binding.item = view
|
RecyclerView.ViewHolder(binding.root) {
|
||||||
|
fun bind(item: BaseItemDto) {
|
||||||
|
binding.item = item
|
||||||
|
binding.itemName.text = if (item.type == "Episode") item.seriesName else item.name
|
||||||
|
binding.itemCount.visibility =
|
||||||
|
if (item.userData?.unplayedItemCount != null) View.VISIBLE else View.GONE
|
||||||
binding.executePendingBindings()
|
binding.executePendingBindings()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object DiffCallback : DiffUtil.ItemCallback<ViewItem>() {
|
companion object DiffCallback : DiffUtil.ItemCallback<BaseItemDto>() {
|
||||||
override fun areItemsTheSame(oldItem: ViewItem, newItem: ViewItem): Boolean {
|
override fun areItemsTheSame(oldItem: BaseItemDto, newItem: BaseItemDto): Boolean {
|
||||||
return oldItem.id == newItem.id
|
return oldItem.id == newItem.id
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun areContentsTheSame(oldItem: ViewItem, newItem: ViewItem): Boolean {
|
override fun areContentsTheSame(oldItem: BaseItemDto, newItem: BaseItemDto): Boolean {
|
||||||
return oldItem == newItem
|
return oldItem == newItem
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
|
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
|
||||||
return ItemViewHolder(BaseItemBinding.inflate(LayoutInflater.from(parent.context), parent, false))
|
return ItemViewHolder(
|
||||||
|
BaseItemBinding.inflate(
|
||||||
|
LayoutInflater.from(parent.context),
|
||||||
|
parent,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||||
|
|
|
@ -12,6 +12,8 @@ class ViewListAdapter : ListAdapter<View, ViewListAdapter.ViewViewHolder>(DiffCa
|
||||||
class ViewViewHolder(private var binding: ViewItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
class ViewViewHolder(private var binding: ViewItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||||
fun bind(view: View) {
|
fun bind(view: View) {
|
||||||
binding.view = view
|
binding.view = view
|
||||||
|
// TODO: Change to string placeholder
|
||||||
|
binding.viewName.text = "Latest ${view.name}"
|
||||||
binding.itemsRecyclerView.adapter = ViewItemListAdapter()
|
binding.itemsRecyclerView.adapter = ViewItemListAdapter()
|
||||||
binding.executePendingBindings()
|
binding.executePendingBindings()
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,5 +6,5 @@ import java.util.*
|
||||||
data class View(
|
data class View(
|
||||||
val id: UUID,
|
val id: UUID,
|
||||||
val name: String?,
|
val name: String?,
|
||||||
var items: List<ViewItem>? = null
|
var items: List<BaseItemDto>? = null
|
||||||
)
|
)
|
|
@ -31,17 +31,10 @@ class HomeViewModel(
|
||||||
val views: MutableList<View> = mutableListOf()
|
val views: MutableList<View> = mutableListOf()
|
||||||
val viewsResult = getViews(jellyfinApi.userId!!)
|
val viewsResult = getViews(jellyfinApi.userId!!)
|
||||||
for (view in viewsResult.items!!) {
|
for (view in viewsResult.items!!) {
|
||||||
val items: MutableList<ViewItem> = mutableListOf()
|
|
||||||
val latestItems = getLatestMedia(jellyfinApi.userId!!, view.id)
|
val latestItems = getLatestMedia(jellyfinApi.userId!!, view.id)
|
||||||
if (latestItems.isEmpty()) continue
|
if (latestItems.isEmpty()) continue
|
||||||
val v = view.toView()
|
val v = view.toView()
|
||||||
for (item in latestItems) {
|
v.items = latestItems
|
||||||
val i = jellyfinApi.api.baseUrl?.let { item.toViewItem(it) }
|
|
||||||
if (i != null) {
|
|
||||||
items.add(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v.items = items
|
|
||||||
views.add(v)
|
views.add(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,21 +61,6 @@ class HomeViewModel(
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun BaseItemDto.toViewItem(baseUrl: String): ViewItem {
|
|
||||||
return when (type) {
|
|
||||||
"Episode" -> ViewItem(
|
|
||||||
id = seriesId!!,
|
|
||||||
name = seriesName,
|
|
||||||
primaryImageUrl = baseUrl.plus("/items/${seriesId}/Images/Primary")
|
|
||||||
)
|
|
||||||
else -> ViewItem(
|
|
||||||
id = id,
|
|
||||||
name = name,
|
|
||||||
primaryImageUrl = baseUrl.plus("/items/${id}/Images/Primary")
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun BaseItemDto.toView(): View {
|
private fun BaseItemDto.toView(): View {
|
||||||
return View(
|
return View(
|
||||||
id = id,
|
id = id,
|
||||||
|
|
5
app/src/main/res/drawable/circle_background.xml
Normal file
5
app/src/main/res/drawable/circle_background.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:shape="oval">
|
||||||
|
<solid android:color="@color/primary" />
|
||||||
|
</shape>
|
|
@ -7,10 +7,10 @@
|
||||||
|
|
||||||
<variable
|
<variable
|
||||||
name="item"
|
name="item"
|
||||||
type="dev.jdtech.jellyfin.models.ViewItem" />
|
type="org.jellyfin.sdk.model.api.BaseItemDto" />
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<LinearLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="150dp"
|
android:layout_width="150dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="12dp"
|
android:layout_marginHorizontal="12dp"
|
||||||
|
@ -20,19 +20,38 @@
|
||||||
android:id="@+id/item_image"
|
android:id="@+id/item_image"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="220dp"
|
android:layout_height="220dp"
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
app:itemImage="@{item}"
|
app:itemImage="@{item}"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearanceOverlay="@style/roundedImageView" />
|
app:shapeAppearanceOverlay="@style/roundedImageView" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/item_name"
|
android:id="@+id/item_name"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
android:ellipsize="end"
|
android:ellipsize="end"
|
||||||
android:maxLines="2"
|
android:maxLines="2"
|
||||||
android:text="@{item.name}"
|
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/item_image"
|
||||||
tools:text="Movie title" />
|
tools:text="Movie title" />
|
||||||
</LinearLayout>
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/item_count"
|
||||||
|
android:layout_width="24dp"
|
||||||
|
android:layout_height="24dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="@drawable/circle_background"
|
||||||
|
android:gravity="center"
|
||||||
|
android:text="@{item.userData.unplayedItemCount.toString()}"
|
||||||
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||||
|
android:textColor="?attr/colorOnPrimary"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="9" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -30,6 +30,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@{collection.name}"
|
android:text="@{collection.name}"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
android:textSize="18sp"
|
||||||
tools:text="Movies" />
|
tools:text="Movies" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
</layout>
|
</layout>
|
|
@ -20,8 +20,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:text="@{view.name}"
|
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
|
android:textSize="18sp"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Movies" />
|
tools:text="Movies" />
|
||||||
|
|
Loading…
Reference in a new issue