Create media info fragment and set up navigation
This commit is contained in:
parent
927c134bd6
commit
ac10b4ba67
10 changed files with 282 additions and 8 deletions
|
@ -10,7 +10,10 @@ import dev.jdtech.jellyfin.R
|
|||
import dev.jdtech.jellyfin.databinding.BaseItemBinding
|
||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||
|
||||
class ViewItemListAdapter(private val fixedWidth: Boolean = false) :
|
||||
class ViewItemListAdapter(
|
||||
private val onClickListener: OnClickListener,
|
||||
private val fixedWidth: Boolean = false,
|
||||
) :
|
||||
ListAdapter<BaseItemDto, ViewItemListAdapter.ItemViewHolder>(DiffCallback) {
|
||||
|
||||
class ItemViewHolder(private var binding: BaseItemBinding, private val parent: ViewGroup) :
|
||||
|
@ -51,6 +54,13 @@ class ViewItemListAdapter(private val fixedWidth: Boolean = false) :
|
|||
|
||||
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
|
||||
val item = getItem(position)
|
||||
holder.itemView.setOnClickListener {
|
||||
onClickListener.onClick(item)
|
||||
}
|
||||
holder.bind(item, fixedWidth)
|
||||
}
|
||||
|
||||
class OnClickListener(val clickListener: (item: BaseItemDto) -> Unit) {
|
||||
fun onClick(item: BaseItemDto) = clickListener(item)
|
||||
}
|
||||
}
|
|
@ -9,14 +9,15 @@ import dev.jdtech.jellyfin.databinding.ViewItemBinding
|
|||
import dev.jdtech.jellyfin.models.View
|
||||
|
||||
class ViewListAdapter(
|
||||
private val onClickListener: OnClickListener
|
||||
private val onClickListener: OnClickListener,
|
||||
private val onItemClickListener: ViewItemListAdapter.OnClickListener
|
||||
) : ListAdapter<View, ViewListAdapter.ViewViewHolder>(DiffCallback) {
|
||||
class ViewViewHolder(private var binding: ViewItemBinding) : RecyclerView.ViewHolder(binding.root) {
|
||||
fun bind(view: View, onClickListener: OnClickListener) {
|
||||
fun bind(view: View, onClickListener: OnClickListener, onItemClickListener: ViewItemListAdapter.OnClickListener) {
|
||||
binding.view = view
|
||||
// TODO: Change to string placeholder
|
||||
binding.viewName.text = "Latest ${view.name}"
|
||||
binding.itemsRecyclerView.adapter = ViewItemListAdapter(fixedWidth = true)
|
||||
binding.itemsRecyclerView.adapter = ViewItemListAdapter(onItemClickListener, fixedWidth = true)
|
||||
binding.viewAll.setOnClickListener {
|
||||
onClickListener.onClick(view)
|
||||
}
|
||||
|
@ -40,7 +41,7 @@ class ViewListAdapter(
|
|||
|
||||
override fun onBindViewHolder(holder: ViewViewHolder, position: Int) {
|
||||
val view = getItem(position)
|
||||
holder.bind(view, onClickListener)
|
||||
holder.bind(view, onClickListener, onItemClickListener)
|
||||
}
|
||||
|
||||
class OnClickListener(val clickListener: (view: View) -> Unit) {
|
||||
|
|
|
@ -8,6 +8,7 @@ import androidx.fragment.app.Fragment
|
|||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import dev.jdtech.jellyfin.R
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||
import dev.jdtech.jellyfin.adapters.ViewListAdapter
|
||||
import dev.jdtech.jellyfin.databinding.FragmentHomeBinding
|
||||
import dev.jdtech.jellyfin.viewmodels.HomeViewModel
|
||||
|
@ -30,6 +31,13 @@ class HomeFragment : Fragment() {
|
|||
it.name
|
||||
)
|
||||
)
|
||||
}, ViewItemListAdapter.OnClickListener {
|
||||
findNavController().navigate(
|
||||
HomeFragmentDirections.actionNavigationHomeToMediaInfoFragment(
|
||||
it.id,
|
||||
it.name
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
binding.errorLayout.findViewById<View>(R.id.retry_button).setOnClickListener {
|
||||
|
|
|
@ -6,6 +6,7 @@ import androidx.fragment.app.Fragment
|
|||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.navigation.fragment.navArgs
|
||||
import dev.jdtech.jellyfin.viewmodels.LibraryViewModel
|
||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||
|
@ -32,9 +33,18 @@ class LibraryFragment : Fragment() {
|
|||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
val viewModelFactory = LibraryViewModelFactory(requireNotNull(this.activity).application, args.libraryId)
|
||||
val viewModelFactory =
|
||||
LibraryViewModelFactory(requireNotNull(this.activity).application, args.libraryId)
|
||||
viewModel = ViewModelProvider(this, viewModelFactory).get(LibraryViewModel::class.java)
|
||||
binding.viewModel = viewModel
|
||||
binding.itemsRecyclerView.adapter = ViewItemListAdapter()
|
||||
binding.itemsRecyclerView.adapter =
|
||||
ViewItemListAdapter(ViewItemListAdapter.OnClickListener {
|
||||
findNavController().navigate(
|
||||
LibraryFragmentDirections.actionLibraryFragmentToMediaInfoFragment(
|
||||
it.id,
|
||||
it.name
|
||||
)
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package dev.jdtech.jellyfin.fragments
|
||||
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import android.os.Bundle
|
||||
import androidx.fragment.app.Fragment
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import dev.jdtech.jellyfin.viewmodels.MediaInfoViewModel
|
||||
import dev.jdtech.jellyfin.R
|
||||
|
||||
class MediaInfoFragment : Fragment() {
|
||||
|
||||
private lateinit var viewModel: MediaInfoViewModel
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
return inflater.inflate(R.layout.fragment_media_info, container, false)
|
||||
}
|
||||
|
||||
override fun onActivityCreated(savedInstanceState: Bundle?) {
|
||||
super.onActivityCreated(savedInstanceState)
|
||||
viewModel = ViewModelProvider(this).get(MediaInfoViewModel::class.java)
|
||||
// TODO: Use the ViewModel
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package dev.jdtech.jellyfin.viewmodels
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
class MediaInfoViewModel : ViewModel() {
|
||||
// TODO: Implement the ViewModel
|
||||
}
|
|
@ -16,6 +16,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="12dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
|
@ -24,10 +25,10 @@
|
|||
android:layout_height="0dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:itemImage="@{item}"
|
||||
app:layout_constraintDimensionRatio="H,2:3"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintDimensionRatio="H,2:3"
|
||||
app:shapeAppearanceOverlay="@style/roundedImageView" />
|
||||
|
||||
<TextView
|
||||
|
|
184
app/src/main/res/layout/fragment_media_info.xml
Normal file
184
app/src/main/res/layout/fragment_media_info.xml
Normal file
|
@ -0,0 +1,184 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<layout>
|
||||
|
||||
<data>
|
||||
|
||||
<variable
|
||||
name="item"
|
||||
type="org.jellyfin.sdk.model.api.BaseItemDto" />
|
||||
</data>
|
||||
|
||||
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="24dp"
|
||||
tools:context=".fragments.MediaInfoFragment">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:text="@{item.originalTitle}"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/year"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@{item.productionYear}"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
tools:text="2019" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/playtime"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@{item.runTimeTicks.toString()}"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
tools:text="122 min" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/official_rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:text="@{item.officialRating}"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
tools:text="PG-13" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/community_rating"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@{item.communityRating.toString()}"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
tools:text="7.3" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/info"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/genres_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/genres_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/genres"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/genres"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="64dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Action, Science Fiction, Adventure" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/director_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="12dp">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/director_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/director"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/director"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="64dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="Robert Rodriguez" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/writers_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/writers_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/writers"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/writers"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="64dp"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:text="James Cameron, Laeta Kalogridis, Yukito Kishiro" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/description"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:text="@{item.overview}"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||
tools:text="An angel falls. A warrior rises. When Alita awakens with no memory of who she is in a future world she does not recognize, she is taken in by Ido, a compassionate doctor who realizes that somewhere in this abandoned cyborg shell is the heart and soul of a young woman with an extraordinary past." />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/cast_amp_crew"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||
android:textSize="18sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</layout>
|
|
@ -17,6 +17,9 @@
|
|||
app:exitAnim="@anim/nav_default_exit_anim"
|
||||
app:popEnterAnim="@anim/nav_default_pop_enter_anim"
|
||||
app:popExitAnim="@anim/nav_default_pop_exit_anim" />
|
||||
<action
|
||||
android:id="@+id/action_navigation_home_to_mediaInfoFragment"
|
||||
app:destination="@id/mediaInfoFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
|
@ -51,5 +54,22 @@
|
|||
android:defaultValue="Library"
|
||||
app:argType="string"
|
||||
app:nullable="true" />
|
||||
<action
|
||||
android:id="@+id/action_libraryFragment_to_mediaInfoFragment"
|
||||
app:destination="@id/mediaInfoFragment" />
|
||||
</fragment>
|
||||
<fragment
|
||||
android:id="@+id/mediaInfoFragment"
|
||||
android:name="dev.jdtech.jellyfin.fragments.MediaInfoFragment"
|
||||
android:label="{itemName}"
|
||||
tools:layout="@layout/fragment_media_info">
|
||||
<argument
|
||||
android:name="itemId"
|
||||
app:argType="java.util.UUID" />
|
||||
<argument
|
||||
android:name="itemName"
|
||||
app:argType="string"
|
||||
app:nullable="true"
|
||||
android:defaultValue="Media Info" />
|
||||
</fragment>
|
||||
</navigation>
|
|
@ -21,4 +21,8 @@
|
|||
<string name="view_all">View all</string>
|
||||
<string name="error_loading_data">Error loading data</string>
|
||||
<string name="retry">Retry</string>
|
||||
<string name="genres">Genres</string>
|
||||
<string name="director">Director</string>
|
||||
<string name="writers">Writers</string>
|
||||
<string name="cast_amp_crew"><![CDATA[Cast & Crew]]></string>
|
||||
</resources>
|
Loading…
Reference in a new issue