Mark items as favorite
This commit is contained in:
parent
f4166d2728
commit
6cf1f5cc49
8 changed files with 100 additions and 0 deletions
|
@ -10,6 +10,7 @@ import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.databinding.EpisodeBottomSheetBinding
|
import dev.jdtech.jellyfin.databinding.EpisodeBottomSheetBinding
|
||||||
import dev.jdtech.jellyfin.viewmodels.EpisodeBottomSheetViewModel
|
import dev.jdtech.jellyfin.viewmodels.EpisodeBottomSheetViewModel
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
@ -40,6 +41,13 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.favoriteButton.setOnClickListener {
|
||||||
|
when (viewModel.favorite.value) {
|
||||||
|
true -> viewModel.unmarkAsFavorite(args.episodeId)
|
||||||
|
false -> viewModel.markAsFavorite(args.episodeId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.item.observe(viewLifecycleOwner, { episode ->
|
viewModel.item.observe(viewLifecycleOwner, { episode ->
|
||||||
if (episode.userData?.playedPercentage != null) {
|
if (episode.userData?.playedPercentage != null) {
|
||||||
binding.progressBar.layoutParams.width = TypedValue.applyDimension(
|
binding.progressBar.layoutParams.width = TypedValue.applyDimension(
|
||||||
|
@ -51,6 +59,15 @@ class EpisodeBottomSheetFragment : BottomSheetDialogFragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.favorite.observe(viewLifecycleOwner, {
|
||||||
|
val drawable = when (it) {
|
||||||
|
true -> R.drawable.ic_heart_filled
|
||||||
|
false -> R.drawable.ic_heart
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.favoriteButton.setImageResource(drawable)
|
||||||
|
})
|
||||||
|
|
||||||
viewModel.loadEpisode(args.episodeId)
|
viewModel.loadEpisode(args.episodeId)
|
||||||
|
|
||||||
return binding.root
|
return binding.root
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.fragment.app.viewModels
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import androidx.navigation.fragment.navArgs
|
import androidx.navigation.fragment.navArgs
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import dev.jdtech.jellyfin.R
|
||||||
import dev.jdtech.jellyfin.adapters.PersonListAdapter
|
import dev.jdtech.jellyfin.adapters.PersonListAdapter
|
||||||
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
import dev.jdtech.jellyfin.adapters.ViewItemListAdapter
|
||||||
import dev.jdtech.jellyfin.databinding.FragmentMediaInfoBinding
|
import dev.jdtech.jellyfin.databinding.FragmentMediaInfoBinding
|
||||||
|
@ -64,6 +65,15 @@ class MediaInfoFragment : Fragment() {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
viewModel.favorite.observe(viewLifecycleOwner, {
|
||||||
|
val drawable = when (it) {
|
||||||
|
true -> R.drawable.ic_heart_filled
|
||||||
|
false -> R.drawable.ic_heart
|
||||||
|
}
|
||||||
|
|
||||||
|
binding.favoriteButton.setImageResource(drawable)
|
||||||
|
})
|
||||||
|
|
||||||
binding.trailerButton.setOnClickListener {
|
binding.trailerButton.setOnClickListener {
|
||||||
val intent = Intent(
|
val intent = Intent(
|
||||||
Intent.ACTION_VIEW,
|
Intent.ACTION_VIEW,
|
||||||
|
@ -101,6 +111,13 @@ class MediaInfoFragment : Fragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
binding.favoriteButton.setOnClickListener {
|
||||||
|
when (viewModel.favorite.value) {
|
||||||
|
true -> viewModel.unmarkAsFavorite(args.itemId)
|
||||||
|
false -> viewModel.markAsFavorite(args.itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
viewModel.loadData(args.itemId, args.itemType)
|
viewModel.loadData(args.itemId, args.itemType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,4 +25,8 @@ interface JellyfinRepository {
|
||||||
suspend fun postPlaybackStop(itemId: UUID, positionTicks: Long)
|
suspend fun postPlaybackStop(itemId: UUID, positionTicks: Long)
|
||||||
|
|
||||||
suspend fun postPlaybackProgress(itemId: UUID, positionTicks: Long, isPaused: Boolean)
|
suspend fun postPlaybackProgress(itemId: UUID, positionTicks: Long, isPaused: Boolean)
|
||||||
|
|
||||||
|
suspend fun markAsFavorite(itemId: UUID)
|
||||||
|
|
||||||
|
suspend fun unmarkAsFavorite(itemId: UUID)
|
||||||
}
|
}
|
|
@ -135,4 +135,16 @@ class JellyfinRepositoryImpl(private val jellyfinApi: JellyfinApi) : JellyfinRep
|
||||||
jellyfinApi.playstateApi.onPlaybackProgress(jellyfinApi.userId!!, itemId, positionTicks = positionTicks, isPaused = isPaused)
|
jellyfinApi.playstateApi.onPlaybackProgress(jellyfinApi.userId!!, itemId, positionTicks = positionTicks, isPaused = isPaused)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun markAsFavorite(itemId: UUID) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
jellyfinApi.userLibraryApi.markFavoriteItem(jellyfinApi.userId!!, itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun unmarkAsFavorite(itemId: UUID) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
jellyfinApi.userLibraryApi.unmarkFavoriteItem(jellyfinApi.userId!!, itemId)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -34,15 +34,33 @@ constructor(
|
||||||
private val _mediaSources = MutableLiveData<List<MediaSourceInfo>>()
|
private val _mediaSources = MutableLiveData<List<MediaSourceInfo>>()
|
||||||
val mediaSources: LiveData<List<MediaSourceInfo>> = _mediaSources
|
val mediaSources: LiveData<List<MediaSourceInfo>> = _mediaSources
|
||||||
|
|
||||||
|
private val _favorite = MutableLiveData<Boolean>()
|
||||||
|
val favorite: LiveData<Boolean> = _favorite
|
||||||
|
|
||||||
fun loadEpisode(episodeId: UUID) {
|
fun loadEpisode(episodeId: UUID) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_item.value = jellyfinRepository.getItem(episodeId)
|
_item.value = jellyfinRepository.getItem(episodeId)
|
||||||
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
||||||
_dateString.value = getDateString(_item.value!!)
|
_dateString.value = getDateString(_item.value!!)
|
||||||
_mediaSources.value = jellyfinRepository.getMediaSources(episodeId)
|
_mediaSources.value = jellyfinRepository.getMediaSources(episodeId)
|
||||||
|
_favorite.value = _item.value?.userData?.isFavorite
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun markAsFavorite(itemId: UUID) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
jellyfinRepository.markAsFavorite(itemId)
|
||||||
|
}
|
||||||
|
_favorite.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unmarkAsFavorite(itemId: UUID) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
jellyfinRepository.unmarkAsFavorite(itemId)
|
||||||
|
}
|
||||||
|
_favorite.value = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun getDateString(item: BaseItemDto): String {
|
private fun getDateString(item: BaseItemDto): String {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
val instant = item.premiereDate?.toInstant(ZoneOffset.UTC)
|
val instant = item.premiereDate?.toInstant(ZoneOffset.UTC)
|
||||||
|
|
|
@ -56,6 +56,9 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
private val _navigateToPlayer = MutableLiveData<MediaSourceInfo>()
|
private val _navigateToPlayer = MutableLiveData<MediaSourceInfo>()
|
||||||
val navigateToPlayer: LiveData<MediaSourceInfo> = _navigateToPlayer
|
val navigateToPlayer: LiveData<MediaSourceInfo> = _navigateToPlayer
|
||||||
|
|
||||||
|
private val _favorite = MutableLiveData<Boolean>()
|
||||||
|
val favorite: LiveData<Boolean> = _favorite
|
||||||
|
|
||||||
fun loadData(itemId: UUID, itemType: String) {
|
fun loadData(itemId: UUID, itemType: String) {
|
||||||
viewModelScope.launch {
|
viewModelScope.launch {
|
||||||
_item.value = jellyfinRepository.getItem(itemId)
|
_item.value = jellyfinRepository.getItem(itemId)
|
||||||
|
@ -67,6 +70,7 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
_genresString.value = _item.value?.genres?.joinToString(separator = ", ")
|
_genresString.value = _item.value?.genres?.joinToString(separator = ", ")
|
||||||
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
_runTime.value = "${_item.value?.runTimeTicks?.div(600000000)} min"
|
||||||
_dateString.value = getDateString(_item.value!!)
|
_dateString.value = getDateString(_item.value!!)
|
||||||
|
_favorite.value = _item.value?.userData?.isFavorite
|
||||||
if (itemType == "Series") {
|
if (itemType == "Series") {
|
||||||
_nextUp.value = getNextUp(itemId)
|
_nextUp.value = getNextUp(itemId)
|
||||||
_seasons.value = jellyfinRepository.getSeasons(itemId)
|
_seasons.value = jellyfinRepository.getSeasons(itemId)
|
||||||
|
@ -110,6 +114,20 @@ constructor(private val jellyfinRepository: JellyfinRepository) : ViewModel() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun markAsFavorite(itemId: UUID) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
jellyfinRepository.markAsFavorite(itemId)
|
||||||
|
}
|
||||||
|
_favorite.value = true
|
||||||
|
}
|
||||||
|
|
||||||
|
fun unmarkAsFavorite(itemId: UUID) {
|
||||||
|
viewModelScope.launch {
|
||||||
|
jellyfinRepository.unmarkAsFavorite(itemId)
|
||||||
|
}
|
||||||
|
_favorite.value = false
|
||||||
|
}
|
||||||
|
|
||||||
private fun getDateString(item: BaseItemDto): String {
|
private fun getDateString(item: BaseItemDto): String {
|
||||||
val dateString: String = item.productionYear.toString()
|
val dateString: String = item.productionYear.toString()
|
||||||
return when (item.status) {
|
return when (item.status) {
|
||||||
|
|
13
app/src/main/res/drawable/ic_heart_filled.xml
Normal file
13
app/src/main/res/drawable/ic_heart_filled.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="M20.42,4.58a5.4,5.4 0,0 0,-7.65 0l-0.77,0.78 -0.77,-0.78a5.4,5.4 0,0 0,-7.65 0C1.46,6.7 1.33,10.28 4,13l8,8 8,-8c2.67,-2.72 2.54,-6.3 0.42,-8.42z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:fillColor="@color/red"
|
||||||
|
android:strokeColor="@color/red"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -13,4 +13,5 @@
|
||||||
<color name="neutral_100">#EEF2F6</color>
|
<color name="neutral_100">#EEF2F6</color>
|
||||||
<color name="black">#FF000000</color>
|
<color name="black">#FF000000</color>
|
||||||
<color name="white">#FFFFFFFF</color>
|
<color name="white">#FFFFFFFF</color>
|
||||||
|
<color name="red">#EB5757</color>
|
||||||
</resources>
|
</resources>
|
Loading…
Reference in a new issue