Improve EpisodeBottomSheet
This commit is contained in:
parent
a3cfe35c13
commit
7c3640fa5f
11 changed files with 112 additions and 46 deletions
|
@ -8,7 +8,7 @@ import androidx.recyclerview.widget.RecyclerView
|
||||||
import dev.jdtech.jellyfin.databinding.EpisodeItemBinding
|
import dev.jdtech.jellyfin.databinding.EpisodeItemBinding
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
|
|
||||||
class EpisodeListAdapter :
|
class EpisodeListAdapter(private val onClickListener: OnClickListener) :
|
||||||
ListAdapter<BaseItemDto, EpisodeListAdapter.EpisodeViewHolder>(DiffCallback) {
|
ListAdapter<BaseItemDto, EpisodeListAdapter.EpisodeViewHolder>(DiffCallback) {
|
||||||
|
|
||||||
class EpisodeViewHolder(private var binding: EpisodeItemBinding) :
|
class EpisodeViewHolder(private var binding: EpisodeItemBinding) :
|
||||||
|
@ -41,6 +41,13 @@ class EpisodeListAdapter :
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: EpisodeViewHolder, position: Int) {
|
override fun onBindViewHolder(holder: EpisodeViewHolder, position: Int) {
|
||||||
val item = getItem(position)
|
val item = getItem(position)
|
||||||
|
holder.itemView.setOnClickListener {
|
||||||
|
onClickListener.onClick(item)
|
||||||
|
}
|
||||||
holder.bind(item)
|
holder.bind(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class OnClickListener(val clickListener: (item: BaseItemDto) -> Unit) {
|
||||||
|
fun onClick(item: BaseItemDto) = clickListener(item)
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -40,11 +40,24 @@ class HomeFragment : Fragment() {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}, HomeEpisodeListAdapter.OnClickListener {
|
}, HomeEpisodeListAdapter.OnClickListener {
|
||||||
findNavController().navigate(
|
when (it.type) {
|
||||||
HomeFragmentDirections.actionNavigationHomeToEpisodeBottomSheetFragment(
|
"Episode" -> {
|
||||||
it.id
|
findNavController().navigate(
|
||||||
)
|
HomeFragmentDirections.actionNavigationHomeToEpisodeBottomSheetFragment(
|
||||||
)
|
it.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
"Movie" -> {
|
||||||
|
findNavController().navigate(
|
||||||
|
HomeFragmentDirections.actionNavigationHomeToMediaInfoFragment(
|
||||||
|
it.id,
|
||||||
|
it.name
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
})
|
})
|
||||||
|
|
||||||
binding.errorLayout.findViewById<View>(R.id.retry_button).setOnClickListener {
|
binding.errorLayout.findViewById<View>(R.id.retry_button).setOnClickListener {
|
||||||
|
|
|
@ -58,6 +58,10 @@ class MediaInfoFragment : Fragment() {
|
||||||
startActivity(intent)
|
startActivity(intent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.nextUp.setOnClickListener {
|
||||||
|
findNavController().navigate(MediaInfoFragmentDirections.actionMediaInfoFragmentToEpisodeBottomSheetFragment(viewModel.nextUp.value!!.id))
|
||||||
|
}
|
||||||
|
|
||||||
binding.seasonsRecyclerView.adapter =
|
binding.seasonsRecyclerView.adapter =
|
||||||
ViewItemListAdapter(ViewItemListAdapter.OnClickListener {
|
ViewItemListAdapter(ViewItemListAdapter.OnClickListener {
|
||||||
findNavController().navigate(
|
findNavController().navigate(
|
||||||
|
|
|
@ -6,6 +6,7 @@ import androidx.fragment.app.Fragment
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import dev.jdtech.jellyfin.adapters.EpisodeListAdapter
|
import dev.jdtech.jellyfin.adapters.EpisodeListAdapter
|
||||||
import dev.jdtech.jellyfin.databinding.FragmentSeasonBinding
|
import dev.jdtech.jellyfin.databinding.FragmentSeasonBinding
|
||||||
|
@ -37,7 +38,14 @@ class SeasonFragment : Fragment() {
|
||||||
)
|
)
|
||||||
viewModel = ViewModelProvider(this, viewModelFactory).get(SeasonViewModel::class.java)
|
viewModel = ViewModelProvider(this, viewModelFactory).get(SeasonViewModel::class.java)
|
||||||
binding.viewModel = viewModel
|
binding.viewModel = viewModel
|
||||||
binding.episodesRecyclerView.adapter = EpisodeListAdapter()
|
binding.episodesRecyclerView.adapter =
|
||||||
|
EpisodeListAdapter(EpisodeListAdapter.OnClickListener {
|
||||||
|
findNavController().navigate(
|
||||||
|
SeasonFragmentDirections.actionSeasonFragmentToEpisodeBottomSheetFragment(
|
||||||
|
it.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
binding.seriesName.text = args.seriesName
|
binding.seriesName.text = args.seriesName
|
||||||
binding.seasonName.text = args.seasonName
|
binding.seasonName.text = args.seasonName
|
||||||
binding.seriesId = args.seriesId
|
binding.seriesId = args.seriesId
|
||||||
|
|
|
@ -11,6 +11,8 @@ import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
|
import java.text.DateFormat
|
||||||
|
import java.time.ZoneOffset
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class EpisodeBottomSheetViewModel(application: Application, episodeId: UUID) : AndroidViewModel(application) {
|
class EpisodeBottomSheetViewModel(application: Application, episodeId: UUID) : AndroidViewModel(application) {
|
||||||
|
@ -42,23 +44,13 @@ class EpisodeBottomSheetViewModel(application: Application, episodeId: UUID) : A
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDateString(item: BaseItemDto): String {
|
private fun getDateString(item: BaseItemDto): String {
|
||||||
val dateString: String = item.productionYear.toString()
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
return when (item.status) {
|
val instant = item.premiereDate?.toInstant(ZoneOffset.UTC)
|
||||||
"Continuing" -> dateString.plus(" - Present")
|
val date = Date.from(instant)
|
||||||
"Ended" -> {
|
DateFormat.getDateInstance(DateFormat.SHORT).format(date)
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
} else {
|
||||||
return if (item.productionYear == item.endDate?.year) {
|
// TODO: Implement a way to get the year from LocalDateTime in Android < O
|
||||||
dateString
|
item.premiereDate.toString()
|
||||||
} else {
|
|
||||||
dateString.plus(" - ${item.endDate?.year}")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// TODO: Implement a way to get the year from LocalDateTime in Android < O
|
|
||||||
dateString
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
else -> dateString
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
13
app/src/main/res/drawable/ic_star.xml
Normal file
13
app/src/main/res/drawable/ic_star.xml
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24">
|
||||||
|
<path
|
||||||
|
android:pathData="M12,2l3.09,6.26l6.91,1.01l-5,4.87l1.18,6.88l-6.18,-3.25l-6.18,3.25l1.18,-6.88l-5,-4.87l6.91,-1.01l3.09,-6.26z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:fillColor="#00000000"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -13,7 +13,8 @@
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
android:paddingBottom="24dp">
|
android:paddingBottom="24dp"
|
||||||
|
android:background="?android:attr/colorBackgroundFloating">
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:id="@+id/episode_image"
|
android:id="@+id/episode_image"
|
||||||
|
@ -22,10 +23,10 @@
|
||||||
android:layout_marginStart="24dp"
|
android:layout_marginStart="24dp"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:scaleType="centerCrop"
|
android:scaleType="centerCrop"
|
||||||
|
app:itemPrimaryImage="@{viewModel.item}"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:shapeAppearance="@style/roundedImageView"
|
app:shapeAppearance="@style/roundedImageView" />
|
||||||
app:itemPrimaryImage="@{viewModel.item}"/>
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/episode_name"
|
android:id="@+id/episode_name"
|
||||||
|
@ -33,8 +34,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="12dp"
|
android:layout_marginStart="12dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
|
android:text="@{String.format(@string/episode_name_extended, viewModel.item.parentIndexNumber, viewModel.item.indexNumber, viewModel.item.name)}"
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
android:text="@{viewModel.item.name}"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toEndOf="@id/episode_image"
|
app:layout_constraintStart_toEndOf="@id/episode_image"
|
||||||
app:layout_constraintTop_toTopOf="@id/episode_image"
|
app:layout_constraintTop_toTopOf="@id/episode_image"
|
||||||
|
@ -45,6 +46,7 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="24dp"
|
android:layout_marginEnd="24dp"
|
||||||
|
android:gravity="bottom"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="@id/episode_name"
|
app:layout_constraintStart_toStartOf="@id/episode_name"
|
||||||
app:layout_constraintTop_toBottomOf="@id/episode_name">
|
app:layout_constraintTop_toBottomOf="@id/episode_name">
|
||||||
|
@ -55,8 +57,8 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
android:text="@{viewModel.dateString}"
|
android:text="@{viewModel.dateString}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
tools:text="4/6/2013" />
|
tools:text="4/6/2013" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -64,16 +66,23 @@
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="8dp"
|
android:layout_marginEnd="8dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
android:text="@{viewModel.runTime}"
|
android:text="@{viewModel.runTime}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
tools:text="26 min" />
|
tools:text="26 min" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_star"
|
||||||
|
app:tint="#F2C94C" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/community_rating"
|
android:id="@+id/community_rating"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
android:text="@{viewModel.item.communityRating.toString()}"
|
android:text="@{viewModel.item.communityRating.toString()}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
tools:text="8.8" />
|
tools:text="8.8" />
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
@ -124,8 +133,8 @@
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginTop="12dp"
|
android:layout_marginTop="12dp"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
|
||||||
android:text="@{viewModel.item.overview}"
|
android:text="@{viewModel.item.overview}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@id/buttons"
|
app:layout_constraintTop_toBottomOf="@id/buttons"
|
||||||
|
|
|
@ -73,7 +73,8 @@
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="16dp">
|
android:layout_marginBottom="16dp"
|
||||||
|
android:gravity="bottom">
|
||||||
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -103,6 +104,13 @@
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
tools:text="PG-13" />
|
tools:text="PG-13" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:importantForAccessibility="no"
|
||||||
|
android:src="@drawable/ic_star"
|
||||||
|
app:tint="#F2C94C" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/community_rating"
|
android:id="@+id/community_rating"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
|
@ -279,8 +287,8 @@
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
|
android:orientation="vertical"
|
||||||
android:visibility="@{viewModel.nextUp != null ? View.VISIBLE : View.GONE}">
|
android:visibility="@{viewModel.nextUp != null ? View.VISIBLE : View.GONE}">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
@ -292,22 +300,29 @@
|
||||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
android:textAppearance="@style/TextAppearance.MaterialComponents.Subtitle1"
|
||||||
android:textSize="18sp" />
|
android:textSize="18sp" />
|
||||||
|
|
||||||
<com.google.android.material.imageview.ShapeableImageView
|
<LinearLayout
|
||||||
|
android:id="@+id/next_up"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:adjustViewBounds="true"
|
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginHorizontal="24dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:foreground="?attr/selectableItemBackground"
|
||||||
app:itemPrimaryImage="@{viewModel.nextUp}"
|
android:orientation="vertical">
|
||||||
app:shapeAppearance="@style/roundedImageView" />
|
|
||||||
|
|
||||||
<TextView
|
<com.google.android.material.imageview.ShapeableImageView
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginHorizontal="24dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:text="@{String.format(@string/episode_name_extended, viewModel.nextUp.parentIndexNumber, viewModel.nextUp.indexNumber, viewModel.nextUp.name)}"
|
android:adjustViewBounds="true"
|
||||||
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
app:itemPrimaryImage="@{viewModel.nextUp}"
|
||||||
tools:text="The Girl Flautist" />
|
app:shapeAppearance="@style/roundedImageView" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@{String.format(@string/episode_name_extended, viewModel.nextUp.parentIndexNumber, viewModel.nextUp.indexNumber, viewModel.nextUp.name)}"
|
||||||
|
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
|
||||||
|
tools:text="The Girl Flautist" />
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
|
|
@ -85,6 +85,9 @@
|
||||||
<action
|
<action
|
||||||
android:id="@+id/action_mediaInfoFragment_to_seasonFragment"
|
android:id="@+id/action_mediaInfoFragment_to_seasonFragment"
|
||||||
app:destination="@id/seasonFragment" />
|
app:destination="@id/seasonFragment" />
|
||||||
|
<action
|
||||||
|
android:id="@+id/action_mediaInfoFragment_to_episodeBottomSheetFragment"
|
||||||
|
app:destination="@id/episodeBottomSheetFragment" />
|
||||||
</fragment>
|
</fragment>
|
||||||
<fragment
|
<fragment
|
||||||
android:id="@+id/seasonFragment"
|
android:id="@+id/seasonFragment"
|
||||||
|
|
|
@ -13,5 +13,6 @@
|
||||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="android:windowBackground">@color/neutral_900</item>
|
<item name="android:windowBackground">@color/neutral_900</item>
|
||||||
|
<item name="android:colorBackgroundFloating">@color/neutral_900</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
|
@ -13,5 +13,6 @@
|
||||||
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
<item name="android:statusBarColor" tools:targetApi="l">?attr/colorPrimaryVariant</item>
|
||||||
<!-- Customize your theme here. -->
|
<!-- Customize your theme here. -->
|
||||||
<item name="android:windowBackground">@color/neutral_100</item>
|
<item name="android:windowBackground">@color/neutral_100</item>
|
||||||
|
<item name="android:colorBackgroundFloating">@color/neutral_100</item>
|
||||||
</style>
|
</style>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue