Skip to content

Commit

Permalink
Discover: extract item view holder and click listener
Browse files Browse the repository at this point in the history
  • Loading branch information
UweTrottmann committed Oct 11, 2024
1 parent afe4727 commit 55f69ba
Show file tree
Hide file tree
Showing 10 changed files with 271 additions and 316 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,9 @@
package com.battlelancer.seriesguide.shows.search.discover

import androidx.fragment.app.Fragment
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.lifecycleScope
import com.battlelancer.seriesguide.enums.NetworkResult
import com.battlelancer.seriesguide.provider.SgRoomDatabase
import com.battlelancer.seriesguide.shows.tools.AddShowTask
import com.battlelancer.seriesguide.shows.tools.ShowTools2
import com.battlelancer.seriesguide.ui.OverviewActivity
import com.battlelancer.seriesguide.util.TaskManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
Expand Down Expand Up @@ -65,36 +57,6 @@ abstract class BaseAddShowsFragment : Fragment() {
}
}

interface ItemClickListener {
fun onItemClick(item: SearchResult)
fun onAddClick(item: SearchResult)
}

protected val itemClickListener = object : ItemClickListener {
override fun onItemClick(item: SearchResult) {
if (item.state != SearchResult.STATE_ADDING) {
if (item.state == SearchResult.STATE_ADDED) {
// Already in library, open it.
lifecycleScope.launch {
val showId = withContext(Dispatchers.IO) {
SgRoomDatabase.getInstance(requireContext()).sgShow2Helper()
.getShowIdByTmdbId(item.tmdbId)
}
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
startActivity(OverviewActivity.intentShow(requireContext(), showId))
}
}
} else {
// Display more details in a dialog.
AddShowDialogFragment.show(parentFragmentManager, item)
}
}
}

override fun onAddClick(item: SearchResult) {
EventBus.getDefault().post(AddFragment.OnAddingShowEvent(item.tmdbId))
TaskManager.getInstance().performAddTask(context, item)
}

}
protected val itemClickListener
get() = ItemAddShowClickListener(requireContext(), lifecycle, parentFragmentManager)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Uwe Trottmann

package com.battlelancer.seriesguide.shows.search.discover

import android.content.Context
import android.view.View
import androidx.fragment.app.FragmentManager
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.coroutineScope
import com.battlelancer.seriesguide.provider.SgRoomDatabase
import com.battlelancer.seriesguide.traktapi.TraktCredentials
import com.battlelancer.seriesguide.ui.OverviewActivity
import com.battlelancer.seriesguide.util.TaskManager
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.EventBus

open class ItemAddShowClickListener(
private val context: Context,
private val lifecycle: Lifecycle,
private val fragmentManager: FragmentManager
) : ItemAddShowViewHolder.ClickListener {

override fun onItemClick(item: SearchResult) {
if (item.state != SearchResult.STATE_ADDING) {
if (item.state == SearchResult.STATE_ADDED) {
// Already in library, open it.
lifecycle.coroutineScope.launch {
val showId = withContext(Dispatchers.IO) {
SgRoomDatabase.getInstance(context).sgShow2Helper()
.getShowIdByTmdbId(item.tmdbId)
}
if (lifecycle.currentState.isAtLeast(Lifecycle.State.STARTED)) {
context.startActivity(OverviewActivity.intentShow(context, showId))
}
}
} else {
// Display more details in a dialog.
AddShowDialogFragment.show(fragmentManager, item)
}
}
}

override fun onAddClick(item: SearchResult) {
EventBus.getDefault().post(AddFragment.OnAddingShowEvent(item.tmdbId))
TaskManager.getInstance().performAddTask(context, item)
}

override fun onMoreOptionsClick(view: View, show: SearchResult) {
val isTraktConnected = TraktCredentials.get(context).hasCredentials()
AddShowPopupMenu(context, show, view).apply {
// this does not know watchlist state, so if at all only show the add to item
hideRemoveFromWatchlistAction()
if (!isTraktConnected) hideAddToWatchlistAction()
}.show()
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Uwe Trottmann

package com.battlelancer.seriesguide.shows.search.discover

import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.TooltipCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.battlelancer.seriesguide.R
import com.battlelancer.seriesguide.databinding.ItemAddshowBinding
import com.battlelancer.seriesguide.util.ImageTools
import com.battlelancer.seriesguide.util.ViewTools.setContextAndLongClickListener

class ItemAddShowViewHolder(
private val binding: ItemAddshowBinding,
private val clickListener: ClickListener
) : RecyclerView.ViewHolder(binding.root) {

private var item: SearchResult? = null

init {
itemView.setOnClickListener {
item?.let { clickListener.onItemClick(it) }
}
binding.addIndicatorAddShow.setOnAddClickListener {
item?.let { clickListener.onAddClick(it) }
}
binding.buttonItemAddMoreOptions.also {
TooltipCompat.setTooltipText(it, it.contentDescription)
}
}

private fun onMoreOptionsClick(anchor: View) {
item?.let {
clickListener.onMoreOptionsClick(anchor, it)
}
}

// Nullable item to support placeholders of paging adapters
fun bindTo(
context: Context,
item: SearchResult?,
showWatchlistActions: Boolean
) {
this.item = item

if (item == null) {
// placeholder data
binding.textViewAddTitle.text = null
binding.textViewAddDescription.text = null
binding.addIndicatorAddShow.isGone = true
binding.imageViewAddPoster.setImageResource(R.drawable.ic_photo_gray_24dp)

itemView.setContextAndLongClickListener(null)
binding.buttonItemAddMoreOptions.isGone = true
return
}

// title and overview
val showTitle = item.title
binding.textViewAddTitle.text = showTitle
binding.textViewAddDescription.text = item.overview

// add button/indicator
binding.addIndicatorAddShow.apply {
setState(item.state)
setNameOfAssociatedItem(showTitle)
isVisible = true
}

// image
ImageTools.loadShowPosterResizeCrop(
context,
binding.imageViewAddPoster,
item.posterPath
)

// context/long press listener and more options button
val canBeAdded = item.state == SearchResult.STATE_ADD
// If not added, always display add action on long press for accessibility
if (canBeAdded) {
itemView.setContextAndLongClickListener {
onMoreOptionsClick(itemView)
}
} else {
// Remove listener to prevent long press feedback
itemView.setContextAndLongClickListener(null)
}
// Only display more options button when displaying watchlist actions
binding.buttonItemAddMoreOptions.apply {
if (showWatchlistActions) {
setOnClickListener {
onMoreOptionsClick(binding.buttonItemAddMoreOptions)
}
isVisible = true
} else {
setOnClickListener(null)
isGone = true
}
}
}

companion object {
fun create(parent: ViewGroup, clickListener: ClickListener) =
ItemAddShowViewHolder(
ItemAddshowBinding.inflate(LayoutInflater.from(parent.context), parent, false),
clickListener
)
}

interface ClickListener {
fun onItemClick(item: SearchResult)
fun onAddClick(item: SearchResult)
fun onMoreOptionsClick(view: View, show: SearchResult)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,24 @@
package com.battlelancer.seriesguide.shows.search.discover

import android.annotation.SuppressLint
import android.content.Context
import android.view.ViewGroup
import androidx.paging.PagingDataAdapter
import androidx.recyclerview.widget.RecyclerView

class SearchResultPagingAdapter(
private val itemClickListener: BaseAddShowsFragment.ItemClickListener
) : PagingDataAdapter<SearchResult, RecyclerView.ViewHolder>(
private val context: Context,
private val itemClickListener: ItemAddShowViewHolder.ClickListener,
private val showWatchlistActions: Boolean
) : PagingDataAdapter<SearchResult, ItemAddShowViewHolder>(
SearchResultDiffCallback()
) {

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return SearchResultViewHolder.create(parent, itemClickListener)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemAddShowViewHolder {
return ItemAddShowViewHolder.create(parent, itemClickListener)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
(holder as SearchResultViewHolder).bindTo(getItem(position))
override fun onBindViewHolder(holder: ItemAddShowViewHolder, position: Int) {
holder.bindTo(context, getItem(position), showWatchlistActions)
}

fun setStateForTmdbId(showTmdbId: Int, newState: Int) {
Expand Down

This file was deleted.

Loading

0 comments on commit 55f69ba

Please sign in to comment.