Skip to content

Commit

Permalink
Merge pull request #1060 from UweTrottmann/discover-add-to-watchlist
Browse files Browse the repository at this point in the history
Discover: consistently provide add show and add to watchlist menu items
  • Loading branch information
UweTrottmann authored Oct 11, 2024
2 parents 208e0f6 + 920f52b commit cf7fdf3
Show file tree
Hide file tree
Showing 15 changed files with 412 additions and 390 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -156,13 +156,13 @@ abstract class AddFragment : Fragment() {
activity: Activity,
objects: List<SearchResult>,
private val itemClickListener: ItemClickListener,
private val enableMoreOptions: Boolean
private val showWatchlistActions: Boolean
) : ArrayAdapter<SearchResult>(activity, 0, objects) {

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

private fun getItemForShowTmdbId(showTmdbId: Int): SearchResult? {
Expand Down Expand Up @@ -208,7 +208,7 @@ abstract class AddFragment : Fragment() {
}

val item = getItem(position)
holder.bindTo(item, context, enableMoreOptions)
holder.bindTo(item, context, showWatchlistActions)

return view
}
Expand All @@ -231,39 +231,46 @@ abstract class AddFragment : Fragment() {
}
}

private fun onMoreOptionsClick() {
private fun onMoreOptionsClick(anchor: View) {
item?.let {
itemClickListener.onMoreOptionsClick(
binding.buttonItemAddMoreOptions,
it.tmdbId
)
itemClickListener.onMoreOptionsClick(anchor, it)
}
}

fun bindTo(item: SearchResult?, context: Context, enableMoreOptions: Boolean) {
fun bindTo(item: SearchResult?, context: Context, showWatchlistActions: Boolean) {
this.item = item

if (enableMoreOptions) {
binding.root.setContextAndLongClickListener {
onMoreOptionsClick()
}
binding.buttonItemAddMoreOptions.setOnClickListener {
onMoreOptionsClick()
}
} else {
// Remove listener so there is no long press feedback
binding.root.setContextAndLongClickListener(null)
binding.buttonItemAddMoreOptions.setOnClickListener(null)
}
binding.buttonItemAddMoreOptions.visibility =
if (enableMoreOptions) View.VISIBLE else View.GONE

if (item == null) {
binding.addIndicatorAddShow.isGone = true
binding.textViewAddTitle.text = null
binding.textViewAddDescription.text = null
binding.imageViewAddPoster.setImageDrawable(null)
} else {
val canBeAdded = item.state == SearchResult.STATE_ADD
// If not added, always display add action on long press for accessibility
binding.root.apply {
if (canBeAdded) {
setContextAndLongClickListener {
onMoreOptionsClick(binding.root)
}
} else {
// Remove listener so there is no long press feedback
setContextAndLongClickListener(null)
}
}
// Only display more options button when displaying remove from watchlist action
binding.buttonItemAddMoreOptions.apply {
if (showWatchlistActions) {
setOnClickListener {
onMoreOptionsClick(binding.buttonItemAddMoreOptions)
}
isVisible = true
} else {
setOnClickListener(null)
isGone = true
}
}

// add indicator
val showTitle = item.title
binding.addIndicatorAddShow.apply {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Uwe Trottmann

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

import android.content.Context
import android.os.AsyncTask
import android.view.MenuItem
import android.view.View
import androidx.appcompat.widget.PopupMenu
import com.battlelancer.seriesguide.R
import com.battlelancer.seriesguide.shows.search.discover.AddFragment.OnAddingShowEvent
import com.battlelancer.seriesguide.util.TaskManager
import com.battlelancer.seriesguide.util.tasks.AddShowToWatchlistTask
import com.battlelancer.seriesguide.util.tasks.RemoveShowFromWatchlistTask
import org.greenrobot.eventbus.EventBus

/**
* A [PopupMenu] with menu items to add a show and add to or remove a show from the Trakt watchlist.
*
* Hides add show item by default based on [show] state.
* Use methods to hide not useful watchlist options.
*/
class AddShowPopupMenu(
private val context: Context,
private val show: SearchResult,
anchor: View
) : PopupMenu(anchor.context, anchor), PopupMenu.OnMenuItemClickListener {

init {
inflate(R.menu.add_show_popup_menu)
if (show.state != SearchResult.STATE_ADD) {
menu.findItem(R.id.menu_action_add_show_add).isVisible = false
}
setOnMenuItemClickListener(this)
}

override fun onMenuItemClick(item: MenuItem): Boolean {
return when (item.itemId) {
R.id.menu_action_add_show_add -> {
// post so other fragments can display a progress indicator for that show
EventBus.getDefault().post(OnAddingShowEvent(show.tmdbId))
TaskManager.getInstance().performAddTask(context, show)
true
}

R.id.menu_action_add_show_watchlist_add -> {
@Suppress("DEPRECATION") // AsyncTask
AddShowToWatchlistTask(context, show.tmdbId)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
true
}

R.id.menu_action_add_show_watchlist_remove -> {
@Suppress("DEPRECATION") // AsyncTask
RemoveShowFromWatchlistTask(context, show.tmdbId)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR)
true
}

else -> false
}
}

fun hideAddToWatchlistAction() {
menu.findItem(R.id.menu_action_add_show_watchlist_add).isVisible = false
}

fun hideRemoveFromWatchlistAction() {
menu.findItem(R.id.menu_action_add_show_watchlist_remove).isVisible = false
}

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

}
Loading

0 comments on commit cf7fdf3

Please sign in to comment.