From f276a26d7d202117563748687b26ed6891aef78c Mon Sep 17 00:00:00 2001 From: Jarne Demeulemeester Date: Sun, 13 Jun 2021 21:26:28 +0200 Subject: [PATCH] Load views and latest items on home screen Needs a lot of optimization and cleanup --- app/build.gradle | 4 ++ .../dev/jdtech/jellyfin/BindingAdapters.kt | 24 ++++++++- .../jellyfin/adapters/ViewItemListAdapter.kt | 38 +++++++++++++ .../jellyfin/adapters/ViewListAdapter.kt | 21 ++++---- .../dev/jdtech/jellyfin/api/JellyfinApi.kt | 6 +-- .../java/dev/jdtech/jellyfin/models/View.kt | 10 ++++ .../dev/jdtech/jellyfin/models/ViewItem.kt | 9 ++++ .../jellyfin/viewmodels/HomeViewModel.kt | 52 +++++++++++++++--- .../viewmodels/ServerSelectViewModel.kt | 2 +- app/src/main/res/layout/activity_main.xml | 54 +++++++++---------- app/src/main/res/layout/base_item.xml | 36 +++++++++++++ app/src/main/res/layout/fragment_home.xml | 2 +- app/src/main/res/layout/view_item.xml | 18 ++++++- app/src/main/res/values/styles.xml | 5 ++ 14 files changed, 228 insertions(+), 53 deletions(-) create mode 100644 app/src/main/java/dev/jdtech/jellyfin/adapters/ViewItemListAdapter.kt create mode 100644 app/src/main/java/dev/jdtech/jellyfin/models/View.kt create mode 100644 app/src/main/java/dev/jdtech/jellyfin/models/ViewItem.kt create mode 100644 app/src/main/res/layout/base_item.xml diff --git a/app/build.gradle b/app/build.gradle index eb2e6a08..3628d9a2 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -66,6 +66,10 @@ dependencies { // Jellyfin implementation "org.jellyfin.sdk:jellyfin-platform-android:$jellyfin_version" + // Glide + implementation 'com.github.bumptech.glide:glide:4.12.0' + kapt 'com.github.bumptech.glide:compiler:4.12.0' + // Testing testImplementation 'junit:junit:4.13.2' androidTestImplementation 'androidx.test.ext:junit:1.1.2' diff --git a/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt b/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt index 15e27745..cb7295fc 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/BindingAdapters.kt @@ -1,10 +1,17 @@ package dev.jdtech.jellyfin +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import android.widget.ImageView import androidx.databinding.BindingAdapter import androidx.recyclerview.widget.RecyclerView +import com.bumptech.glide.Glide import dev.jdtech.jellyfin.database.Server import dev.jdtech.jellyfin.adapters.ServerGridAdapter +import dev.jdtech.jellyfin.adapters.ViewItemListAdapter import dev.jdtech.jellyfin.adapters.ViewListAdapter +import dev.jdtech.jellyfin.models.View +import dev.jdtech.jellyfin.models.ViewItem import org.jellyfin.sdk.model.api.BaseItemDto @BindingAdapter("servers") @@ -14,7 +21,22 @@ fun bindServers(recyclerView: RecyclerView, data: List?) { } @BindingAdapter("views") -fun bindViews(recyclerView: RecyclerView, data: List?) { +fun bindViews(recyclerView: RecyclerView, data: List?) { val adapter = recyclerView.adapter as ViewListAdapter adapter.submitList(data) +} + +@BindingAdapter("items") +fun bindItems(recyclerView: RecyclerView, data: List?) { + val adapter = recyclerView.adapter as ViewItemListAdapter + adapter.submitList(data) +} + +@BindingAdapter("itemImage") +fun bindItemImage(imageView: ImageView, item: ViewItem) { + Glide + .with(imageView.context) + .load(item.primaryImageUrl) + .placeholder(ColorDrawable(Color.GRAY)) + .into(imageView) } \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewItemListAdapter.kt b/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewItemListAdapter.kt new file mode 100644 index 00000000..49de8167 --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewItemListAdapter.kt @@ -0,0 +1,38 @@ +package dev.jdtech.jellyfin.adapters + +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.recyclerview.widget.DiffUtil +import androidx.recyclerview.widget.ListAdapter +import androidx.recyclerview.widget.RecyclerView +import dev.jdtech.jellyfin.databinding.BaseItemBinding +import dev.jdtech.jellyfin.models.ViewItem +import org.jellyfin.sdk.model.api.BaseItemDto + +class ViewItemListAdapter : ListAdapter(DiffCallback) { + class ItemViewHolder(private var binding: BaseItemBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(view: ViewItem) { + binding.item = view + binding.executePendingBindings() + } + } + + companion object DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: ViewItem, newItem: ViewItem): Boolean { + return oldItem.id == newItem.id + } + + override fun areContentsTheSame(oldItem: ViewItem, newItem: ViewItem): Boolean { + return oldItem == newItem + } + } + + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder { + return ItemViewHolder(BaseItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)) + } + + override fun onBindViewHolder(holder: ItemViewHolder, position: Int) { + val item = getItem(position) + holder.bind(item) + } +} \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt b/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt index b5635eed..c3067e82 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/adapters/ViewListAdapter.kt @@ -6,31 +6,32 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView import dev.jdtech.jellyfin.databinding.ViewItemBinding -import org.jellyfin.sdk.model.api.BaseItemDto +import dev.jdtech.jellyfin.models.View -class ViewListAdapter : ListAdapter(DiffCallback) { - class ViewHolder(private var binding: ViewItemBinding) : RecyclerView.ViewHolder(binding.root) { - fun bind(view: BaseItemDto) { +class ViewListAdapter : ListAdapter(DiffCallback) { + class ViewViewHolder(private var binding: ViewItemBinding) : RecyclerView.ViewHolder(binding.root) { + fun bind(view: View) { binding.view = view + binding.itemsRecyclerView.adapter = ViewItemListAdapter() binding.executePendingBindings() } } - companion object DiffCallback : DiffUtil.ItemCallback() { - override fun areItemsTheSame(oldItem: BaseItemDto, newItem: BaseItemDto): Boolean { + companion object DiffCallback : DiffUtil.ItemCallback() { + override fun areItemsTheSame(oldItem: View, newItem: View): Boolean { return oldItem.id == newItem.id } - override fun areContentsTheSame(oldItem: BaseItemDto, newItem: BaseItemDto): Boolean { + override fun areContentsTheSame(oldItem: View, newItem: View): Boolean { return oldItem == newItem } } - override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { - return ViewHolder(ViewItemBinding.inflate(LayoutInflater.from(parent.context))) + override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewViewHolder { + return ViewViewHolder(ViewItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)) } - override fun onBindViewHolder(holder: ViewHolder, position: Int) { + override fun onBindViewHolder(holder: ViewViewHolder, position: Int) { val view = getItem(position) holder.bind(view) } diff --git a/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt b/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt index 6403e0ca..70d149a4 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/api/JellyfinApi.kt @@ -5,9 +5,7 @@ import android.util.Log import dev.jdtech.jellyfin.BuildConfig import org.jellyfin.sdk.Jellyfin import org.jellyfin.sdk.android -import org.jellyfin.sdk.api.operations.SystemApi -import org.jellyfin.sdk.api.operations.UserApi -import org.jellyfin.sdk.api.operations.UserViewsApi +import org.jellyfin.sdk.api.operations.* import org.jellyfin.sdk.model.ClientInfo import java.util.* @@ -31,6 +29,8 @@ class JellyfinApi(context: Context, baseUrl: String) { val systemApi = SystemApi(api) val userApi = UserApi(api) val viewsApi = UserViewsApi(api) + val itemsApi = ItemsApi(api) + val userLibraryApi = UserLibraryApi(api) init { Log.i("JellyfinApi", "Constructor called!") diff --git a/app/src/main/java/dev/jdtech/jellyfin/models/View.kt b/app/src/main/java/dev/jdtech/jellyfin/models/View.kt new file mode 100644 index 00000000..2afd44c3 --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/models/View.kt @@ -0,0 +1,10 @@ +package dev.jdtech.jellyfin.models + +import org.jellyfin.sdk.model.api.BaseItemDto +import java.util.* + +data class View( + val id: UUID, + val name: String?, + var items: List? = null +) \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/models/ViewItem.kt b/app/src/main/java/dev/jdtech/jellyfin/models/ViewItem.kt new file mode 100644 index 00000000..f48e3b2d --- /dev/null +++ b/app/src/main/java/dev/jdtech/jellyfin/models/ViewItem.kt @@ -0,0 +1,9 @@ +package dev.jdtech.jellyfin.models + +import java.util.* + +data class ViewItem( + val id: UUID, + val name: String?, + val primaryImageUrl: String +) \ No newline at end of file diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt index c2181bd3..5af781a7 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/HomeViewModel.kt @@ -1,11 +1,11 @@ package dev.jdtech.jellyfin.viewmodels import android.app.Application -import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData -import androidx.lifecycle.ViewModel -import androidx.lifecycle.viewModelScope +import android.util.Log +import androidx.lifecycle.* import dev.jdtech.jellyfin.api.JellyfinApi +import dev.jdtech.jellyfin.models.View +import dev.jdtech.jellyfin.models.ViewItem import kotlinx.coroutines.launch import org.jellyfin.sdk.model.api.BaseItemDto @@ -14,14 +14,50 @@ class HomeViewModel( ) : ViewModel() { private val jellyfinApi = JellyfinApi.getInstance(application, "") - private val _views = MutableLiveData>() - val views: LiveData> = _views + private val _views = MutableLiveData>() + val views: LiveData> = _views + + private val _items = MutableLiveData>() + val items: LiveData> = _items init { viewModelScope.launch { + val views: MutableList = mutableListOf() + val result by jellyfinApi.viewsApi.getUserViews(jellyfinApi.userId!!) - _views.value = result.items + for (view in result.items!!) { + val items: MutableList = mutableListOf() + val resultItems by jellyfinApi.userLibraryApi.getLatestMedia(jellyfinApi.userId!!, parentId = view.id) + if (resultItems.isEmpty()) continue + val v = view.toView() + for (item in resultItems) { + val i = jellyfinApi.api.baseUrl?.let { item.toViewItem(it) } + if (i != null) { + items.add(i) + } + } + v.items = items + views.add(v) + } + + _views.value = views + } } -} \ No newline at end of file +} + +private fun BaseItemDto.toViewItem(baseUrl: String) : ViewItem { + return ViewItem( + id = id, + name = name, + primaryImageUrl = baseUrl.plus("/items/${id}/Images/Primary") + ) +} + +private fun BaseItemDto.toView() : View { + return View( + id = id, + name = name + ) +} diff --git a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt index 80993dae..32546afb 100644 --- a/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt +++ b/app/src/main/java/dev/jdtech/jellyfin/viewmodels/ServerSelectViewModel.kt @@ -37,7 +37,7 @@ class ServerSelectViewModel( } fun connectToServer(server: Server) { - JellyfinApi.getInstance(application, server.address).apply { + JellyfinApi.newInstance(application, server.address).apply { api.accessToken = server.accessToken userId = UUID.fromString(server.userId) } diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 113303ed..3ef155f3 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -2,34 +2,34 @@ - - - - - + android:paddingTop="?attr/actionBarSize"> - + + + + + diff --git a/app/src/main/res/layout/base_item.xml b/app/src/main/res/layout/base_item.xml new file mode 100644 index 00000000..908ca425 --- /dev/null +++ b/app/src/main/res/layout/base_item.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index dca99714..230219c2 100644 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -17,7 +17,7 @@ + type="dev.jdtech.jellyfin.models.View" /> + android:layout_height="wrap_content" + android:layout_marginBottom="42dp"> + + \ No newline at end of file diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index eac3faef..fd4f903e 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -26,4 +26,9 @@ 48dp @drawable/button_setup_background + + \ No newline at end of file