Mark items as favorite

This commit is contained in:
Jarne Demeulemeester 2021-07-16 14:45:35 +02:00
parent f4166d2728
commit 6cf1f5cc49
No known key found for this signature in database
GPG key ID: 60884A0C1EBA43E5
8 changed files with 100 additions and 0 deletions

View file

@ -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

View file

@ -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)
} }

View file

@ -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)
} }

View file

@ -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)
}
}
} }

View file

@ -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)

View file

@ -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) {

View 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>

View file

@ -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>